mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
99 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
22dcbac16f | ||
![]() |
44faedd6c0 | ||
![]() |
fb3b673e63 | ||
![]() |
4e377f86d1 | ||
![]() |
e8bd98020b | ||
![]() |
c520034934 | ||
![]() |
5d5fd403b8 | ||
![]() |
1fc02229df | ||
![]() |
6c8d3db3a4 | ||
![]() |
c5b69561af | ||
![]() |
b5bffff941 | ||
![]() |
1a2cdc8c0e | ||
![]() |
50ab62f103 | ||
![]() |
5005d83ce0 | ||
![]() |
d7e40e488c | ||
![]() |
4958e22770 | ||
![]() |
a5e3f94228 | ||
![]() |
9e57b2c17e | ||
![]() |
e1ff366e10 | ||
![]() |
6b03b01a24 | ||
![]() |
18f01b7f21 | ||
![]() |
897f691d6c | ||
![]() |
a9902d9109 | ||
![]() |
5d78fdd6a4 | ||
![]() |
72eb013371 | ||
![]() |
808777c044 | ||
![]() |
a2d1379866 | ||
![]() |
c41a8556fa | ||
![]() |
fa2df2a3cd | ||
![]() |
b28dd3a723 | ||
![]() |
6ffa41e0d6 | ||
![]() |
85df3794e8 | ||
![]() |
4bee2ba062 | ||
![]() |
4bf992c4a9 | ||
![]() |
898e856150 | ||
![]() |
c86797afc8 | ||
![]() |
799593b788 | ||
![]() |
74d9a083aa | ||
![]() |
cae525429a | ||
![]() |
cc0d1e2a9b | ||
![]() |
34ecfcfa16 | ||
![]() |
79c5041216 | ||
![]() |
8fb53260ab | ||
![]() |
07d9ac823a | ||
![]() |
b571ef434c | ||
![]() |
c1f4dcd6a6 | ||
![]() |
4c5befbe44 | ||
![]() |
296cd4d0a3 | ||
![]() |
e77a2ca34a | ||
![]() |
f3af0d18bc | ||
![]() |
406e3c7e6b | ||
![]() |
3f5ca8ebfa | ||
![]() |
6e8389e833 | ||
![]() |
71aedca4c6 | ||
![]() |
6410689549 | ||
![]() |
6d0e2269cc | ||
![]() |
2e28fc678c | ||
![]() |
8204f4407f | ||
![]() |
9f1d4c4db2 | ||
![]() |
8ba47635d3 | ||
![]() |
5fa2427c51 | ||
![]() |
aa8739d016 | ||
![]() |
79f0329da7 | ||
![]() |
7a33a36f44 | ||
![]() |
808424d08e | ||
![]() |
d0967785de | ||
![]() |
eccabb8189 | ||
![]() |
c9374ff515 | ||
![]() |
92c4889924 | ||
![]() |
f9454039a1 | ||
![]() |
bc4511e175 | ||
![]() |
f191103f99 | ||
![]() |
408463f63b | ||
![]() |
fb96c4272e | ||
![]() |
c6b302d5a8 | ||
![]() |
1dd468e2ff | ||
![]() |
2a1aa8c649 | ||
![]() |
1633734e08 | ||
![]() |
dff92e6f27 | ||
![]() |
dba5e30d5d | ||
![]() |
2d04ab2e72 | ||
![]() |
1a015ac8d3 | ||
![]() |
6390620ddd | ||
![]() |
0d19005dc3 | ||
![]() |
c6479dd2c4 | ||
![]() |
8871331b7c | ||
![]() |
e01148b86a | ||
![]() |
2f87e3818e | ||
![]() |
2c8a594c38 | ||
![]() |
1508dab7fe | ||
![]() |
958b21e47e | ||
![]() |
781c3311ae | ||
![]() |
52850d172e | ||
![]() |
52a065542e | ||
![]() |
fd10469685 | ||
![]() |
a2ee75b113 | ||
![]() |
0f7f243b98 | ||
![]() |
97d7996a50 | ||
![]() |
b658d164f9 |
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
@@ -9,10 +9,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: setup node
|
- name: setup node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ jobs:
|
|||||||
- name: zip
|
- name: zip
|
||||||
run: |
|
run: |
|
||||||
sudo apt install zip -y
|
sudo apt install zip -y
|
||||||
cp manifest.json ./dist/manifest.json
|
|
||||||
cd ./dist/
|
cd ./dist/
|
||||||
zip -r ../LLOneBot.zip ./*
|
zip -r ../LLOneBot.zip ./*
|
||||||
|
|
||||||
|
15
.gitignore
vendored
15
.gitignore
vendored
@@ -1,6 +1,15 @@
|
|||||||
node_modules/
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
dist/
|
yarn.lock
|
||||||
out/
|
node_modules
|
||||||
|
dist
|
||||||
|
out
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
1
.yarnrc.yml
Normal file
1
.yarnrc.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
nodeLinker: node-modules
|
32
README.md
32
README.md
@@ -1,9 +1,9 @@
|
|||||||
# LLOneBot
|
# LLOneBot
|
||||||
|
|
||||||
LiteLoaderQQNT插件,使你的NTQQ支持OneBot11协议进行QQ机器人开发
|
LiteLoaderQQNT 插件,实现 OneBot 11 协议,用以 QQ 机器人开发
|
||||||
|
|
||||||
> [!CAUTION]\
|
> [!CAUTION]\
|
||||||
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于:B站,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息**
|
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: B站,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息**
|
||||||
|
|
||||||
TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
||||||
|
|
||||||
@@ -13,35 +13,16 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
|||||||
|
|
||||||
## 设置界面
|
## 设置界面
|
||||||
|
|
||||||
<img src="./doc/image/setting.png" width="500px" alt="图片名称"/>
|
<img src="./doc/image/setting.png" width="400px" alt="设置界面"/>
|
||||||
|
|
||||||
## HTTP 调用示例
|
## HTTP 调用示例
|
||||||
|
|
||||||

|
<img src="./doc/image/example.jpg" width="500px" alt="HTTP调用示例"/>
|
||||||
|
|
||||||
## 支持的 api 和功能详情
|
## 支持的 API
|
||||||
|
|
||||||
见 <https://llonebot.github.io/zh-CN/develop/api>
|
见 <https://llonebot.github.io/zh-CN/develop/api>
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- [x] 重构摆脱LLAPI,目前调用LLAPI只能在renderer进程调用,需重构成在main进程调用
|
|
||||||
- [x] 支持正、反向websocket(感谢@disymayufei的PR)
|
|
||||||
- [x] 转发消息记录
|
|
||||||
- [x] 好友点赞api
|
|
||||||
- [x] 群管理功能,禁言、踢人,改群名片等
|
|
||||||
- [x] 视频消息
|
|
||||||
- [x] 文件消息
|
|
||||||
- [x] 群禁言事件上报
|
|
||||||
- [x] 优化加群成功事件上报
|
|
||||||
- [x] 清理缓存api
|
|
||||||
- [ ] 无头模式
|
|
||||||
- [ ] 框架对接文档
|
|
||||||
|
|
||||||
## onebot11文档
|
|
||||||
|
|
||||||
<https://11.onebot.dev/>
|
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|
||||||
[](https://starchart.cc/LLOneBot/LLOneBot)
|
[](https://starchart.cc/LLOneBot/LLOneBot)
|
||||||
@@ -49,8 +30,7 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
|||||||
## 鸣谢
|
## 鸣谢
|
||||||
|
|
||||||
- [LiteLoaderQQNT](https://liteloaderqqnt.github.io/guide/install.html)
|
- [LiteLoaderQQNT](https://liteloaderqqnt.github.io/guide/install.html)
|
||||||
- [LLAPI](https://github.com/Night-stars-1/LiteLoaderQQNT-Plugin-LLAPI)
|
- [chronocat](https://github.com/chrononeko/chronocat)
|
||||||
- [chronocat](https://github.com/chrononeko/chronocat/)
|
|
||||||
- [koishi-plugin-adapter-onebot](https://github.com/koishijs/koishi-plugin-adapter-onebot)
|
- [koishi-plugin-adapter-onebot](https://github.com/koishijs/koishi-plugin-adapter-onebot)
|
||||||
- [silk-wasm](https://github.com/idranme/silk-wasm)
|
- [silk-wasm](https://github.com/idranme/silk-wasm)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import cp from 'vite-plugin-cp'
|
import cp from 'vite-plugin-cp'
|
||||||
import './scripts/gen-version'
|
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
import './scripts/gen-manifest'
|
||||||
|
|
||||||
const external = [
|
const external = [
|
||||||
'silk-wasm',
|
'silk-wasm',
|
||||||
@@ -32,6 +32,7 @@ let config = {
|
|||||||
external,
|
external,
|
||||||
input: 'src/main/main.ts',
|
input: 'src/main/main.ts',
|
||||||
},
|
},
|
||||||
|
minify: true,
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@@ -44,8 +45,8 @@ let config = {
|
|||||||
targets: [
|
targets: [
|
||||||
...external.map(genCpModule),
|
...external.map(genCpModule),
|
||||||
{ src: './manifest.json', dest: 'dist' },
|
{ src: './manifest.json', dest: 'dist' },
|
||||||
{ src: './icon.jpg', dest: 'dist' },
|
{ src: './icon.webp', dest: 'dist' },
|
||||||
{ src: './src/ntqqapi/native/crychic/crychic-win32-x64.node', dest: 'dist/main/' },
|
// { src: './src/ntqqapi/native/crychic/crychic-win32-x64.node', dest: 'dist/main/' },
|
||||||
// { src: './src/ntqqapi/native/moehook/MoeHoo-win32-x64.node', dest: 'dist/main/' },
|
// { src: './src/ntqqapi/native/moehook/MoeHoo-win32-x64.node', dest: 'dist/main/' },
|
||||||
// { src: './src/ntqqapi/native/moehook/MoeHoo-linux-x64.node', dest: 'dist/main/' },
|
// { src: './src/ntqqapi/native/moehook/MoeHoo-linux-x64.node', dest: 'dist/main/' },
|
||||||
],
|
],
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 4,
|
"manifest_version": 4,
|
||||||
"type": "extension",
|
"type": "extension",
|
||||||
"name": "LLOneBot v3.26.5",
|
"name": "LLOneBot",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新",
|
"description": "实现 OneBot 11 协议,用以 QQ 机器人开发",
|
||||||
"version": "3.26.5",
|
"version": "3.28.1",
|
||||||
"icon": "./icon.jpg",
|
"icon": "./icon.webp",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "linyuchen",
|
"name": "linyuchen",
|
||||||
|
39
package.json
39
package.json
@@ -16,34 +16,27 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"compressing": "^1.10.0",
|
"compressing": "^1.10.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.19.2",
|
||||||
"fast-xml-parser": "^4.3.6",
|
"fast-xml-parser": "^4.4.1",
|
||||||
"file-type": "^19.0.0",
|
"file-type": "^19.4.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"level": "^8.0.1",
|
"level": "^8.0.1",
|
||||||
"silk-wasm": "^3.3.4",
|
"silk-wasm": "^3.6.1",
|
||||||
"utf-8-validate": "^6.0.3",
|
"ws": "^8.18.0"
|
||||||
"uuid": "^9.0.1",
|
|
||||||
"ws": "^8.16.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.20",
|
"@types/cors": "^2.8.17",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/fluent-ffmpeg": "^2.1.25",
|
||||||
"@types/node": "^20.11.24",
|
"@types/node": "^20.11.24",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/ws": "^8.5.12",
|
||||||
"@types/ws": "^8.5.10",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
|
||||||
"electron": "^29.0.1",
|
"electron": "^29.0.1",
|
||||||
"electron-vite": "^2.0.0",
|
"electron-vite": "^2.3.0",
|
||||||
"eslint": "^8.0.1",
|
"typescript": "^5.5.4",
|
||||||
"eslint-plugin-import": "^2.25.2",
|
"vite": "^5.4.0",
|
||||||
"eslint-plugin-n": "^15.0.0 || ^16.0.0",
|
|
||||||
"eslint-plugin-promise": "^6.0.0",
|
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"typescript": "*",
|
|
||||||
"vite": "^5.1.4",
|
|
||||||
"vite-plugin-cp": "^4.0.8"
|
"vite-plugin-cp": "^4.0.8"
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@4.4.0"
|
||||||
}
|
}
|
||||||
|
38
scripts/gen-manifest.ts
Normal file
38
scripts/gen-manifest.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { version } from '../src/version'
|
||||||
|
import { writeFileSync } from 'node:fs'
|
||||||
|
|
||||||
|
const manifest = {
|
||||||
|
manifest_version: 4,
|
||||||
|
type: 'extension',
|
||||||
|
name: 'LLOneBot',
|
||||||
|
slug: 'LLOneBot',
|
||||||
|
description: '实现 OneBot 11 协议,用以 QQ 机器人开发',
|
||||||
|
version,
|
||||||
|
icon: './icon.webp',
|
||||||
|
authors: [
|
||||||
|
{
|
||||||
|
name: 'linyuchen',
|
||||||
|
link: 'https://github.com/linyuchen'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
repository: {
|
||||||
|
repo: 'linyuchen/LiteLoaderQQNT-OneBotApi',
|
||||||
|
branch: 'main',
|
||||||
|
release: {
|
||||||
|
tag: 'latest',
|
||||||
|
name: 'LLOneBot.zip'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
platform: [
|
||||||
|
'win32',
|
||||||
|
'linux',
|
||||||
|
'darwin'
|
||||||
|
],
|
||||||
|
injects: {
|
||||||
|
renderer: './renderer/index.js',
|
||||||
|
main: './main/main.cjs',
|
||||||
|
preload: './preload/preload.cjs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync('manifest.json', JSON.stringify(manifest, null, 2))
|
@@ -1,22 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import { version } from '../src/version'
|
|
||||||
|
|
||||||
const manifestPath = path.join(__dirname, '../manifest.json')
|
|
||||||
|
|
||||||
function readManifest(): any {
|
|
||||||
if (fs.existsSync(manifestPath)) {
|
|
||||||
return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeManifest(manifest: any) {
|
|
||||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
const manifest = readManifest()
|
|
||||||
if (version !== manifest.version) {
|
|
||||||
manifest.version = version
|
|
||||||
manifest.name = `LLOneBot v${version}`
|
|
||||||
writeManifest(manifest)
|
|
||||||
}
|
|
@@ -1,10 +1,10 @@
|
|||||||
import { Level } from 'level'
|
import { Level } from 'level'
|
||||||
|
|
||||||
const db = new Level(process.env['level_db_path'], { valueEncoding: 'json' })
|
const db = new Level(process.env['level_db_path'] as string, { valueEncoding: 'json' })
|
||||||
|
|
||||||
async function getGroupNotify() {
|
async function getGroupNotify() {
|
||||||
let keys = await db.keys().all()
|
let keys = await db.keys().all()
|
||||||
let result = []
|
let result: string[] = []
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
// console.log(key)
|
// console.log(key)
|
||||||
if (key.startsWith('group_notify_')) {
|
if (key.startsWith('group_notify_')) {
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import fsPromise from 'fs/promises'
|
|
||||||
import { Config, OB11Config } from './types'
|
import { Config, OB11Config } from './types'
|
||||||
|
|
||||||
import { mergeNewProperties } from './utils/helper'
|
import { mergeNewProperties } from './utils/helper'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { selfInfo } from './data'
|
import { selfInfo } from './data'
|
||||||
@@ -43,6 +41,7 @@ export class ConfigUtil {
|
|||||||
enableQOAutoQuote: false
|
enableQOAutoQuote: false
|
||||||
}
|
}
|
||||||
let defaultConfig: Config = {
|
let defaultConfig: Config = {
|
||||||
|
enableLLOB: true,
|
||||||
ob11: ob11Default,
|
ob11: ob11Default,
|
||||||
heartInterval: 60000,
|
heartInterval: 60000,
|
||||||
token: '',
|
token: '',
|
||||||
@@ -52,7 +51,6 @@ export class ConfigUtil {
|
|||||||
reportSelfMessage: false,
|
reportSelfMessage: false,
|
||||||
autoDeleteFile: false,
|
autoDeleteFile: false,
|
||||||
autoDeleteFileSecond: 60,
|
autoDeleteFileSecond: 60,
|
||||||
enablePoke: false,
|
|
||||||
musicSignUrl: '',
|
musicSignUrl: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,8 @@ export const llonebotError: LLOneBotError = {
|
|||||||
wsServerError: '',
|
wsServerError: '',
|
||||||
otherError: 'LLOnebot未能正常启动,请检查日志查看错误',
|
otherError: 'LLOnebot未能正常启动,请检查日志查看错误',
|
||||||
}
|
}
|
||||||
|
// 群号 -> 群成员map(uid=>GroupMember)
|
||||||
|
export const groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>()
|
||||||
|
|
||||||
export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
|
export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
|
||||||
let filterKey = isNumeric(uinOrUid.toString()) ? 'uin' : 'uid'
|
let filterKey = isNumeric(uinOrUid.toString()) ? 'uin' : 'uid'
|
||||||
@@ -45,7 +47,7 @@ export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
|
|||||||
if (friend) {
|
if (friend) {
|
||||||
friends.push(friend)
|
friends.push(friend)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('刷新好友列表失败', e.stack.toString())
|
log('刷新好友列表失败', e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,34 +81,32 @@ export function deleteGroup(groupCode: string) {
|
|||||||
export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) {
|
export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) {
|
||||||
groupQQ = groupQQ.toString()
|
groupQQ = groupQQ.toString()
|
||||||
memberUinOrUid = memberUinOrUid.toString()
|
memberUinOrUid = memberUinOrUid.toString()
|
||||||
const group = await getGroup(groupQQ)
|
let members = groupMembers.get(groupQQ)
|
||||||
if (group) {
|
if (!members) {
|
||||||
const filterKey = isNumeric(memberUinOrUid) ? 'uin' : 'uid'
|
|
||||||
const filterValue = memberUinOrUid
|
|
||||||
let filterFunc: (member: GroupMember) => boolean = (member) => member[filterKey] === filterValue
|
|
||||||
let member = group.members?.find(filterFunc)
|
|
||||||
if (!member) {
|
|
||||||
try {
|
try {
|
||||||
const _members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||||
if (_members.length > 0) {
|
// 更新群成员列表
|
||||||
group.members = _members
|
groupMembers.set(groupQQ, members)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
catch (e) {
|
||||||
// log("刷新群成员列表失败", e.stack.toString())
|
return null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
member = group.members?.find(filterFunc)
|
const getMember = () => {
|
||||||
|
let member: GroupMember | undefined = undefined
|
||||||
|
if (isNumeric(memberUinOrUid)) {
|
||||||
|
member = Array.from(members!.values()).find(member => member.uin === memberUinOrUid)
|
||||||
|
} else {
|
||||||
|
member = members!.get(memberUinOrUid)
|
||||||
}
|
}
|
||||||
return member
|
return member
|
||||||
}
|
}
|
||||||
return null
|
let member = getMember()
|
||||||
}
|
if (!member) {
|
||||||
|
members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||||
export async function refreshGroupMembers(groupQQ: string) {
|
member = getMember()
|
||||||
const group = groups.find((group) => group.groupCode === groupQQ)
|
|
||||||
if (group) {
|
|
||||||
group.members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
|
||||||
}
|
}
|
||||||
|
return member
|
||||||
}
|
}
|
||||||
|
|
||||||
export const uidMaps: Record<string, string> = {} // 一串加密的字符串(uid) -> qq号
|
export const uidMaps: Record<string, string> = {} // 一串加密的字符串(uid) -> qq号
|
||||||
|
@@ -14,9 +14,9 @@ class DBUtil {
|
|||||||
public readonly DB_KEY_PREFIX_FILE = 'file_'
|
public readonly DB_KEY_PREFIX_FILE = 'file_'
|
||||||
public readonly DB_KEY_PREFIX_GROUP_NOTIFY = 'group_notify_'
|
public readonly DB_KEY_PREFIX_GROUP_NOTIFY = 'group_notify_'
|
||||||
private readonly DB_KEY_RECEIVED_TEMP_UIN_MAP = 'received_temp_uin_map'
|
private readonly DB_KEY_RECEIVED_TEMP_UIN_MAP = 'received_temp_uin_map'
|
||||||
public db: Level
|
public db: Level | undefined
|
||||||
public cache: Record<string, RawMessage | string | FileCache | GroupNotify | ReceiveTempUinMap> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: RawMessage
|
public cache: Record<string, RawMessage | string | FileCache | GroupNotify | ReceiveTempUinMap> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: RawMessage
|
||||||
private currentShortId: number
|
private currentShortId: number | undefined
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 数据库结构
|
* 数据库结构
|
||||||
@@ -44,7 +44,7 @@ class DBUtil {
|
|||||||
this.db = new Level(DB_PATH, { valueEncoding: 'json' })
|
this.db = new Level(DB_PATH, { valueEncoding: 'json' })
|
||||||
console.log('llonebot init db success')
|
console.log('llonebot init db success')
|
||||||
resolve(null)
|
resolve(null)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.log('init db fail', e.stack.toString())
|
console.log('init db fail', e.stack.toString())
|
||||||
setTimeout(initDB, 300)
|
setTimeout(initDB, 300)
|
||||||
}
|
}
|
||||||
@@ -72,13 +72,13 @@ class DBUtil {
|
|||||||
|
|
||||||
public async getReceivedTempUinMap(): Promise<ReceiveTempUinMap> {
|
public async getReceivedTempUinMap(): Promise<ReceiveTempUinMap> {
|
||||||
try {
|
try {
|
||||||
this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] = JSON.parse(await this.db.get(this.DB_KEY_RECEIVED_TEMP_UIN_MAP))
|
this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] = JSON.parse(await this.db?.get(this.DB_KEY_RECEIVED_TEMP_UIN_MAP)!)
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
return (this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] || {}) as ReceiveTempUinMap
|
return (this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] || {}) as ReceiveTempUinMap
|
||||||
}
|
}
|
||||||
public setReceivedTempUinMap(data: ReceiveTempUinMap) {
|
public setReceivedTempUinMap(data: ReceiveTempUinMap) {
|
||||||
this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] = data
|
this.cache[this.DB_KEY_RECEIVED_TEMP_UIN_MAP] = data
|
||||||
this.db.put(this.DB_KEY_RECEIVED_TEMP_UIN_MAP, JSON.stringify(data)).then()
|
this.db?.put(this.DB_KEY_RECEIVED_TEMP_UIN_MAP, JSON.stringify(data)).then()
|
||||||
}
|
}
|
||||||
private addCache(msg: RawMessage) {
|
private addCache(msg: RawMessage) {
|
||||||
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
||||||
@@ -91,30 +91,30 @@ class DBUtil {
|
|||||||
this.cache = {}
|
this.cache = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMsgByShortId(shortMsgId: number): Promise<RawMessage> {
|
async getMsgByShortId(shortMsgId: number): Promise<RawMessage | undefined> {
|
||||||
const shortMsgIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId
|
const shortMsgIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId
|
||||||
if (this.cache[shortMsgIdKey]) {
|
if (this.cache[shortMsgIdKey]) {
|
||||||
// log("getMsgByShortId cache", shortMsgIdKey, this.cache[shortMsgIdKey])
|
// log("getMsgByShortId cache", shortMsgIdKey, this.cache[shortMsgIdKey])
|
||||||
return this.cache[shortMsgIdKey] as RawMessage
|
return this.cache[shortMsgIdKey] as RawMessage
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const longId = await this.db.get(shortMsgIdKey)
|
const longId = await this.db?.get(shortMsgIdKey)
|
||||||
const msg = await this.getMsgByLongId(longId)
|
const msg = await this.getMsgByLongId(longId!)
|
||||||
this.addCache(msg)
|
this.addCache(msg!)
|
||||||
return msg
|
return msg
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('getMsgByShortId db error', e.stack.toString())
|
log('getMsgByShortId db error', e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMsgByLongId(longId: string): Promise<RawMessage> {
|
async getMsgByLongId(longId: string): Promise<RawMessage | undefined> {
|
||||||
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + longId
|
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + longId
|
||||||
if (this.cache[longIdKey]) {
|
if (this.cache[longIdKey]) {
|
||||||
return this.cache[longIdKey] as RawMessage
|
return this.cache[longIdKey] as RawMessage
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const data = await this.db.get(longIdKey)
|
const data = await this.db?.get(longIdKey)
|
||||||
const msg = JSON.parse(data)
|
const msg = JSON.parse(data!)
|
||||||
this.addCache(msg)
|
this.addCache(msg)
|
||||||
return msg
|
return msg
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -122,17 +122,17 @@ class DBUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMsgBySeqId(seqId: string): Promise<RawMessage> {
|
async getMsgBySeqId(seqId: string): Promise<RawMessage | undefined> {
|
||||||
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + seqId
|
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + seqId
|
||||||
if (this.cache[seqIdKey]) {
|
if (this.cache[seqIdKey]) {
|
||||||
return this.cache[seqIdKey] as RawMessage
|
return this.cache[seqIdKey] as RawMessage
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const longId = await this.db.get(seqIdKey)
|
const longId = await this.db?.get(seqIdKey)
|
||||||
const msg = await this.getMsgByLongId(longId)
|
const msg = await this.getMsgByLongId(longId!)
|
||||||
this.addCache(msg)
|
this.addCache(msg!)
|
||||||
return msg
|
return msg
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('getMsgBySeqId db error', e.stack.toString())
|
log('getMsgBySeqId db error', e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ class DBUtil {
|
|||||||
// 有则更新,无则添加
|
// 有则更新,无则添加
|
||||||
// log("addMsg", msg.msgId, msg.msgSeq, msg.msgShortId);
|
// log("addMsg", msg.msgId, msg.msgSeq, msg.msgShortId);
|
||||||
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
||||||
let existMsg = this.cache[longIdKey] as RawMessage
|
let existMsg: RawMessage | undefined = this.cache[longIdKey] as RawMessage
|
||||||
if (!existMsg) {
|
if (!existMsg) {
|
||||||
try {
|
try {
|
||||||
existMsg = await this.getMsgByLongId(msg.msgId)
|
existMsg = await this.getMsgByLongId(msg.msgId)
|
||||||
@@ -161,13 +161,13 @@ class DBUtil {
|
|||||||
msg.msgShortId = shortMsgId
|
msg.msgShortId = shortMsgId
|
||||||
this.addCache(msg)
|
this.addCache(msg)
|
||||||
// log("新增消息记录", msg.msgId)
|
// log("新增消息记录", msg.msgId)
|
||||||
this.db.put(shortIdKey, msg.msgId).then().catch()
|
this.db?.put(shortIdKey, msg.msgId).then().catch()
|
||||||
this.db.put(longIdKey, JSON.stringify(msg)).then().catch()
|
this.db?.put(longIdKey, JSON.stringify(msg)).then().catch()
|
||||||
try {
|
try {
|
||||||
await this.db.get(seqIdKey)
|
await this.db?.get(seqIdKey)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// log("新的seqId", seqIdKey)
|
// log("新的seqId", seqIdKey)
|
||||||
this.db.put(seqIdKey, msg.msgId).then().catch()
|
this.db?.put(seqIdKey, msg.msgId).then().catch()
|
||||||
}
|
}
|
||||||
if (!this.cache[seqIdKey]) {
|
if (!this.cache[seqIdKey]) {
|
||||||
this.cache[seqIdKey] = msg
|
this.cache[seqIdKey] = msg
|
||||||
@@ -178,7 +178,7 @@ class DBUtil {
|
|||||||
|
|
||||||
async updateMsg(msg: RawMessage) {
|
async updateMsg(msg: RawMessage) {
|
||||||
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
|
||||||
let existMsg = this.cache[longIdKey] as RawMessage
|
let existMsg: RawMessage | undefined = this.cache[longIdKey] as RawMessage
|
||||||
if (!existMsg) {
|
if (!existMsg) {
|
||||||
try {
|
try {
|
||||||
existMsg = await this.getMsgByLongId(msg.msgId)
|
existMsg = await this.getMsgByLongId(msg.msgId)
|
||||||
@@ -187,18 +187,18 @@ class DBUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(existMsg, msg)
|
Object.assign(existMsg!, msg)
|
||||||
this.db.put(longIdKey, JSON.stringify(existMsg)).then().catch()
|
this.db?.put(longIdKey, JSON.stringify(existMsg)).then().catch()
|
||||||
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + existMsg.msgShortId
|
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + existMsg?.msgShortId
|
||||||
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq
|
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq
|
||||||
if (!this.cache[seqIdKey]) {
|
if (!this.cache[seqIdKey]) {
|
||||||
this.cache[seqIdKey] = existMsg
|
this.cache[seqIdKey] = existMsg!
|
||||||
}
|
}
|
||||||
this.db.put(shortIdKey, msg.msgId).then().catch()
|
this.db?.put(shortIdKey, msg.msgId).then().catch()
|
||||||
try {
|
try {
|
||||||
await this.db.get(seqIdKey)
|
await this.db?.get(seqIdKey)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.db.put(seqIdKey, msg.msgId).then().catch()
|
this.db?.put(seqIdKey, msg.msgId).then().catch()
|
||||||
// log("更新seqId error", e.stack, seqIdKey);
|
// log("更新seqId error", e.stack, seqIdKey);
|
||||||
}
|
}
|
||||||
// log("更新消息", existMsg.msgSeq, existMsg.msgShortId, existMsg.msgId);
|
// log("更新消息", existMsg.msgSeq, existMsg.msgShortId, existMsg.msgId);
|
||||||
@@ -208,15 +208,15 @@ class DBUtil {
|
|||||||
const key = 'msg_current_short_id'
|
const key = 'msg_current_short_id'
|
||||||
if (this.currentShortId === undefined) {
|
if (this.currentShortId === undefined) {
|
||||||
try {
|
try {
|
||||||
let id: string = await this.db.get(key)
|
const id = await this.db?.get(key)
|
||||||
this.currentShortId = parseInt(id)
|
this.currentShortId = parseInt(id!)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.currentShortId = -2147483640
|
this.currentShortId = -2147483640
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentShortId++
|
this.currentShortId++
|
||||||
this.db.put(key, this.currentShortId.toString()).then().catch()
|
this.db?.put(key, this.currentShortId.toString()).then().catch()
|
||||||
return this.currentShortId
|
return this.currentShortId
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +229,8 @@ class DBUtil {
|
|||||||
delete cacheDBData['downloadFunc']
|
delete cacheDBData['downloadFunc']
|
||||||
this.cache[fileNameOrUuid] = data
|
this.cache[fileNameOrUuid] = data
|
||||||
try {
|
try {
|
||||||
await this.db.put(key, JSON.stringify(cacheDBData))
|
await this.db?.put(key, JSON.stringify(cacheDBData))
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('addFileCache db error', e.stack.toString())
|
log('addFileCache db error', e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,8 +241,8 @@ class DBUtil {
|
|||||||
return this.cache[key] as FileCache
|
return this.cache[key] as FileCache
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let data = await this.db.get(key)
|
const data = await this.db?.get(key)
|
||||||
return JSON.parse(data)
|
return JSON.parse(data!)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// log("getFileCache db error", e.stack.toString())
|
// log("getFileCache db error", e.stack.toString())
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ class DBUtil {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.cache[key] = notify
|
this.cache[key] = notify
|
||||||
this.db.put(key, JSON.stringify(notify)).then().catch()
|
this.db?.put(key, JSON.stringify(notify)).then().catch()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupNotify(seq: string): Promise<GroupNotify | undefined> {
|
async getGroupNotify(seq: string): Promise<GroupNotify | undefined> {
|
||||||
@@ -264,8 +264,8 @@ class DBUtil {
|
|||||||
return this.cache[key] as GroupNotify
|
return this.cache[key] as GroupNotify
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let data = await this.db.get(key)
|
const data = await this.db?.get(key)
|
||||||
return JSON.parse(data)
|
return JSON.parse(data!)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// log("getGroupNotify db error", e.stack.toString())
|
// log("getGroupNotify db error", e.stack.toString())
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import express, { Express, Request, Response } from 'express'
|
import express, { Express, Request, Response } from 'express'
|
||||||
import http from 'http'
|
import http from 'node:http'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import { log } from '../utils/log'
|
import { log } from '../utils/log'
|
||||||
import { getConfigUtil } from '../config'
|
import { getConfigUtil } from '../config'
|
||||||
@@ -10,7 +10,7 @@ type RegisterHandler = (res: Response, payload: any) => Promise<any>
|
|||||||
export abstract class HttpServerBase {
|
export abstract class HttpServerBase {
|
||||||
name: string = 'LLOneBot'
|
name: string = 'LLOneBot'
|
||||||
private readonly expressAPP: Express
|
private readonly expressAPP: Express
|
||||||
private server: http.Server = null
|
private server: http.Server | null = null
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.expressAPP = express()
|
this.expressAPP = express()
|
||||||
@@ -38,7 +38,7 @@ export abstract class HttpServerBase {
|
|||||||
let clientToken = ''
|
let clientToken = ''
|
||||||
const authHeader = req.get('authorization')
|
const authHeader = req.get('authorization')
|
||||||
if (authHeader) {
|
if (authHeader) {
|
||||||
clientToken = authHeader.split('Bearer ').pop()
|
clientToken = authHeader.split('Bearer ').pop()!
|
||||||
log('receive http header token', clientToken)
|
log('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)) {
|
||||||
@@ -58,11 +58,11 @@ export abstract class HttpServerBase {
|
|||||||
start(port: number) {
|
start(port: number) {
|
||||||
try {
|
try {
|
||||||
this.expressAPP.get('/', (req: Request, res: Response) => {
|
this.expressAPP.get('/', (req: Request, res: Response) => {
|
||||||
res.send(`${this.name}已启动`)
|
res.send(`${this.name} 已启动`)
|
||||||
})
|
})
|
||||||
this.listen(port)
|
this.listen(port)
|
||||||
llonebotError.httpServerError = ''
|
llonebotError.httpServerError = ''
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('HTTP服务启动失败', e.toString())
|
log('HTTP服务启动失败', e.toString())
|
||||||
llonebotError.httpServerError = 'HTTP服务启动失败, ' + e.toString()
|
llonebotError.httpServerError = 'HTTP服务启动失败, ' + e.toString()
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ export abstract class HttpServerBase {
|
|||||||
log('收到http请求', url, payload)
|
log('收到http请求', url, payload)
|
||||||
try {
|
try {
|
||||||
res.send(await handler(res, payload))
|
res.send(await handler(res, payload))
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
this.handleFailed(res, payload, e.stack.toString())
|
this.handleFailed(res, payload, e.stack.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -6,9 +6,9 @@ import { getConfigUtil } from '../config'
|
|||||||
import { llonebotError } from '../data'
|
import { llonebotError } from '../data'
|
||||||
|
|
||||||
class WebsocketClientBase {
|
class WebsocketClientBase {
|
||||||
private wsClient: WebSocket
|
private wsClient: WebSocket | undefined
|
||||||
|
|
||||||
constructor() {}
|
constructor() { }
|
||||||
|
|
||||||
send(msg: string) {
|
send(msg: string) {
|
||||||
if (this.wsClient && this.wsClient.readyState == WebSocket.OPEN) {
|
if (this.wsClient && this.wsClient.readyState == WebSocket.OPEN) {
|
||||||
@@ -16,11 +16,11 @@ class WebsocketClientBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage(msg: string) {}
|
onMessage(msg: string) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebsocketServerBase {
|
export class WebsocketServerBase {
|
||||||
private ws: WebSocketServer = null
|
private ws: WebSocketServer | null = null
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log(`llonebot websocket service started`)
|
console.log(`llonebot websocket service started`)
|
||||||
@@ -30,22 +30,22 @@ export class WebsocketServerBase {
|
|||||||
try {
|
try {
|
||||||
this.ws = new WebSocketServer({ port, maxPayload: 1024 * 1024 * 1024 })
|
this.ws = new WebSocketServer({ port, maxPayload: 1024 * 1024 * 1024 })
|
||||||
llonebotError.wsServerError = ''
|
llonebotError.wsServerError = ''
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
llonebotError.wsServerError = '正向ws服务启动失败, ' + e.toString()
|
llonebotError.wsServerError = '正向ws服务启动失败, ' + e.toString()
|
||||||
}
|
}
|
||||||
this.ws.on('connection', (wsClient, req) => {
|
this.ws?.on('connection', (wsClient, req) => {
|
||||||
const url = req.url.split('?').shift()
|
const url = req.url?.split('?').shift()
|
||||||
this.authorize(wsClient, req)
|
this.authorize(wsClient, req)
|
||||||
this.onConnect(wsClient, url, req)
|
this.onConnect(wsClient, url!, req)
|
||||||
wsClient.on('message', async (msg) => {
|
wsClient.on('message', async (msg) => {
|
||||||
this.onMessage(wsClient, url, msg.toString())
|
this.onMessage(wsClient, url!, msg.toString())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
llonebotError.wsServerError = ''
|
llonebotError.wsServerError = ''
|
||||||
this.ws.close((err) => {
|
this.ws?.close((err) => {
|
||||||
log('ws server close failed!', err)
|
log('ws server close failed!', err)
|
||||||
})
|
})
|
||||||
this.ws = null
|
this.ws = null
|
||||||
@@ -83,11 +83,11 @@ export class WebsocketServerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeFailed(wsClient: WebSocket) {}
|
authorizeFailed(wsClient: WebSocket) { }
|
||||||
|
|
||||||
onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) {}
|
onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) { }
|
||||||
|
|
||||||
onMessage(wsClient: WebSocket, url: string, msg: string) {}
|
onMessage(wsClient: WebSocket, url: string, msg: string) { }
|
||||||
|
|
||||||
sendHeart() {}
|
sendHeart() { }
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ export interface CheckVersion {
|
|||||||
version: string
|
version: string
|
||||||
}
|
}
|
||||||
export interface Config {
|
export interface Config {
|
||||||
|
enableLLOB: boolean
|
||||||
ob11: OB11Config
|
ob11: OB11Config
|
||||||
token?: string
|
token?: string
|
||||||
heartInterval?: number // ms
|
heartInterval?: number // ms
|
||||||
@@ -27,7 +28,6 @@ export interface Config {
|
|||||||
autoDeleteFile?: boolean
|
autoDeleteFile?: boolean
|
||||||
autoDeleteFileSecond?: number
|
autoDeleteFileSecond?: number
|
||||||
ffmpeg?: string // ffmpeg路径
|
ffmpeg?: string // ffmpeg路径
|
||||||
enablePoke?: boolean
|
|
||||||
musicSignUrl?: string
|
musicSignUrl?: string
|
||||||
ignoreBeforeLoginMsg?: boolean
|
ignoreBeforeLoginMsg?: boolean
|
||||||
}
|
}
|
||||||
|
231
src/common/utils/EventTask.ts
Normal file
231
src/common/utils/EventTask.ts
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import { NodeIQQNTWrapperSession } from '@/ntqqapi/wrapper'
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
|
interface Internal_MapKey {
|
||||||
|
timeout: number
|
||||||
|
createtime: number
|
||||||
|
func: (...arg: any[]) => any
|
||||||
|
checker: ((...args: any[]) => boolean) | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListenerClassBase {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListenerIBase {
|
||||||
|
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) {
|
||||||
|
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("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args)
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.forEach((task, uuid) => {
|
||||||
|
//console.log(task.func, uuid, task.createtime, task.timeout)
|
||||||
|
if (task.createtime + task.timeout < Date.now()) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (task.checker && task.checker(...args)) {
|
||||||
|
task.func(...args)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
|
const EventFunc = this.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 RegisterListen<ListenerType extends (...args: any[]) => void>(ListenerName = '', waitTimes = 1, timeout = 5000, checker: (...args: Parameters<ListenerType>) => boolean) {
|
||||||
|
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||||
|
const ListenerNameList = ListenerName.split('/')
|
||||||
|
const ListenerMainName = ListenerNameList[0]
|
||||||
|
const ListenerSubName = ListenerNameList[1]
|
||||||
|
const id = randomUUID()
|
||||||
|
let complete = 0
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error(' ListenerName:' + ListenerName + ' timeout'))
|
||||||
|
} else {
|
||||||
|
resolve(retData!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Timeouter = setTimeout(databack, timeout)
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: Parameters<ListenerType>) => {
|
||||||
|
complete++
|
||||||
|
retData = args
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>
|
||||||
|
(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters<ListenerType>) => boolean, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||||
|
const id = randomUUID()
|
||||||
|
let complete = 0
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined
|
||||||
|
let retEvent: any = {}
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error('Timeout: NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n'))
|
||||||
|
} else {
|
||||||
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListenerNameList = ListenerName.split('/')
|
||||||
|
const ListenerMainName = ListenerNameList[0]
|
||||||
|
const ListenerSubName = ListenerNameList[1]
|
||||||
|
|
||||||
|
const Timeouter = setTimeout(databack, timeout)
|
||||||
|
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: any[]) => {
|
||||||
|
complete++
|
||||||
|
//console.log('func', ...args)
|
||||||
|
retData = args as Parameters<ListenerType>
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter)
|
||||||
|
databack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map())
|
||||||
|
}
|
||||||
|
if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map())
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak)
|
||||||
|
this.CreatListenerFunction(ListenerMainName)
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName)
|
||||||
|
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) })
|
@@ -33,17 +33,17 @@ if (typeof configVersionInfoPath !== 'string') {
|
|||||||
export { configVersionInfoPath }
|
export { configVersionInfoPath }
|
||||||
|
|
||||||
type QQPkgInfo = {
|
type QQPkgInfo = {
|
||||||
version: string;
|
version: string
|
||||||
buildVersion: string;
|
buildVersion: string
|
||||||
platform: string;
|
platform: string
|
||||||
eleArch: string;
|
eleArch: string
|
||||||
}
|
}
|
||||||
type QQVersionConfigInfo = {
|
type QQVersionConfigInfo = {
|
||||||
baseVersion: string;
|
baseVersion: string
|
||||||
curVersion: string;
|
curVersion: string
|
||||||
prevVersion: string;
|
prevVersion: string
|
||||||
onErrorVersions: Array<any>;
|
onErrorVersions: Array<any>
|
||||||
buildId: string;
|
buildId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
||||||
@@ -81,3 +81,7 @@ if (systemPlatform === 'linux') {
|
|||||||
// todo: mac 平台的 appid
|
// todo: mac 平台的 appid
|
||||||
export const appid = _appid
|
export const appid = _appid
|
||||||
export const isQQ998: boolean = qqPkgInfo.buildVersion >= '22106'
|
export const isQQ998: boolean = qqPkgInfo.buildVersion >= '22106'
|
||||||
|
|
||||||
|
export function getBuildVersion(): number {
|
||||||
|
return +qqPkgInfo.buildVersion
|
||||||
|
}
|
@@ -1,130 +1,119 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm'
|
|
||||||
import fsPromise from 'fs/promises'
|
|
||||||
import { log } from './log'
|
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { DATA_DIR, TEMP_DIR } from './index'
|
import ffmpeg from 'fluent-ffmpeg'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import fsPromise from 'node:fs/promises'
|
||||||
|
import { decode, encode, getDuration, getWavFileInfo, isWav, isSilk, EncodeResult } from 'silk-wasm'
|
||||||
|
import { log } from './log'
|
||||||
|
import { TEMP_DIR } from './index'
|
||||||
import { getConfigUtil } from '../config'
|
import { getConfigUtil } from '../config'
|
||||||
import { spawn } from 'node:child_process'
|
import { randomUUID } from 'node:crypto'
|
||||||
|
import { Readable } from 'node:stream'
|
||||||
|
|
||||||
|
interface FFmpegOptions {
|
||||||
|
input?: string[]
|
||||||
|
output?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input = string | Readable
|
||||||
|
|
||||||
|
function convert(input: Input, options: FFmpegOptions): Promise<Buffer>
|
||||||
|
function convert(input: Input, options: FFmpegOptions, outputPath: string): Promise<string>
|
||||||
|
function convert(input: Input, options: FFmpegOptions, outputPath?: string): Promise<Buffer> | Promise<string> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
const chunks: Buffer[] = []
|
||||||
|
let command = ffmpeg(input)
|
||||||
|
.on('error', err => {
|
||||||
|
log(`FFmpeg处理转换出错: `, err.message)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
if (!outputPath) {
|
||||||
|
resolve(Buffer.concat(chunks))
|
||||||
|
} else {
|
||||||
|
resolve(outputPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (options.input) {
|
||||||
|
command = command.inputOptions(options.input)
|
||||||
|
}
|
||||||
|
if (options.output) {
|
||||||
|
command = command.outputOptions(options.output)
|
||||||
|
}
|
||||||
|
const ffmpegPath = getConfigUtil().getConfig().ffmpeg
|
||||||
|
if (ffmpegPath) {
|
||||||
|
command = command.setFfmpegPath(ffmpegPath)
|
||||||
|
}
|
||||||
|
if (!outputPath) {
|
||||||
|
const stream = command.pipe()
|
||||||
|
stream.on('data', chunk => {
|
||||||
|
chunks.push(chunk)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
command.save(outputPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export async function encodeSilk(filePath: string) {
|
export async function encodeSilk(filePath: string) {
|
||||||
function getFileHeader(filePath: string) {
|
|
||||||
// 定义要读取的字节数
|
|
||||||
const bytesToRead = 7
|
|
||||||
try {
|
try {
|
||||||
const buffer = fs.readFileSync(filePath, {
|
const file = await fsPromise.readFile(filePath)
|
||||||
encoding: null,
|
if (!isSilk(file)) {
|
||||||
flag: 'r',
|
|
||||||
})
|
|
||||||
|
|
||||||
const fileHeader = buffer.toString('hex', 0, bytesToRead)
|
|
||||||
return fileHeader
|
|
||||||
} catch (err) {
|
|
||||||
console.error('读取文件错误:', err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isWavFile(filePath: string) {
|
|
||||||
return isWav(fs.readFileSync(filePath))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function guessDuration(pttPath: string) {
|
|
||||||
const pttFileInfo = await fsPromise.stat(pttPath)
|
|
||||||
let duration = pttFileInfo.size / 1024 / 3 // 3kb/s
|
|
||||||
duration = Math.floor(duration)
|
|
||||||
duration = Math.max(1, duration)
|
|
||||||
log(`通过文件大小估算语音的时长:`, duration)
|
|
||||||
return duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// function verifyDuration(oriDuration: number, guessDuration: number) {
|
|
||||||
// // 单位都是秒
|
|
||||||
// if (oriDuration - guessDuration > 10) {
|
|
||||||
// return guessDuration
|
|
||||||
// }
|
|
||||||
// oriDuration = Math.max(1, oriDuration)
|
|
||||||
// return oriDuration
|
|
||||||
// }
|
|
||||||
// async function getAudioSampleRate(filePath: string) {
|
|
||||||
// try {
|
|
||||||
// const mm = await import('music-metadata');
|
|
||||||
// const metadata = await mm.parseFile(filePath);
|
|
||||||
// log(`${filePath}采样率`, metadata.format.sampleRate);
|
|
||||||
// return metadata.format.sampleRate;
|
|
||||||
// } catch (error) {
|
|
||||||
// log(`${filePath}采样率获取失败`, error.stack);
|
|
||||||
// // console.error(error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
try {
|
|
||||||
const pttPath = path.join(TEMP_DIR, uuidv4())
|
|
||||||
if (getFileHeader(filePath) !== '02232153494c4b') {
|
|
||||||
log(`语音文件${filePath}需要转换成silk`)
|
log(`语音文件${filePath}需要转换成silk`)
|
||||||
const _isWav = await isWavFile(filePath)
|
let result: EncodeResult
|
||||||
const pcmPath = pttPath + '.pcm'
|
|
||||||
let sampleRate = 0
|
|
||||||
const convert = () => {
|
|
||||||
return new Promise<Buffer>((resolve, reject) => {
|
|
||||||
const ffmpegPath = getConfigUtil().getConfig().ffmpeg || process.env.FFMPEG_PATH || 'ffmpeg'
|
|
||||||
const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath])
|
|
||||||
cp.on('error', (err) => {
|
|
||||||
log(`FFmpeg处理转换出错: `, err.message)
|
|
||||||
return reject(err)
|
|
||||||
})
|
|
||||||
cp.on('exit', (code, signal) => {
|
|
||||||
const EXIT_CODES = [0, 255]
|
|
||||||
if (code == null || EXIT_CODES.includes(code)) {
|
|
||||||
sampleRate = 24000
|
|
||||||
const data = fs.readFileSync(pcmPath)
|
|
||||||
fs.unlink(pcmPath, (err) => {})
|
|
||||||
return resolve(data)
|
|
||||||
}
|
|
||||||
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`)
|
|
||||||
reject(Error(`FFmpeg处理转换失败`))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let input: Buffer
|
|
||||||
if (!_isWav) {
|
|
||||||
input = await convert()
|
|
||||||
} else {
|
|
||||||
input = fs.readFileSync(filePath)
|
|
||||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
||||||
const { fmt } = getWavFileInfo(input)
|
if (isWav(file) && allowSampleRate.includes(getWavFileInfo(file).fmt.sampleRate)) {
|
||||||
// log(`wav文件信息`, fmt)
|
result = await encode(file, 0)
|
||||||
if (!allowSampleRate.includes(fmt.sampleRate)) {
|
} else {
|
||||||
input = await convert()
|
const input = await convert(filePath, {
|
||||||
|
output: [
|
||||||
|
'-ar 24000',
|
||||||
|
'-ac 1',
|
||||||
|
'-f s16le'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
result = await encode(input, 24000)
|
||||||
}
|
}
|
||||||
}
|
const pttPath = path.join(TEMP_DIR, randomUUID())
|
||||||
const silk = await encode(input, sampleRate)
|
await fsPromise.writeFile(pttPath, result.data)
|
||||||
fs.writeFileSync(pttPath, silk.data)
|
log(`语音文件${filePath}转换成功!`, pttPath, `时长:`, result.duration)
|
||||||
log(`语音文件${filePath}转换成功!`, pttPath, `时长:`, silk.duration)
|
|
||||||
return {
|
return {
|
||||||
converted: true,
|
converted: true,
|
||||||
path: pttPath,
|
path: pttPath,
|
||||||
duration: silk.duration / 1000,
|
duration: result.duration / 1000,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const silk = fs.readFileSync(filePath)
|
const silk = file
|
||||||
let duration = 0
|
let duration = 1
|
||||||
try {
|
try {
|
||||||
duration = getDuration(silk) / 1000
|
duration = getDuration(silk) / 1000
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack)
|
log('获取语音文件时长失败, 默认为1秒', filePath, e.stack)
|
||||||
duration = await guessDuration(filePath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
converted: false,
|
converted: false,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
duration,
|
duration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
log('convert silk failed', error.stack)
|
log('convert silk failed', error.stack)
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OutFormat = 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
||||||
|
|
||||||
|
export async function decodeSilk(inputFilePath: string, outFormat: OutFormat = 'mp3') {
|
||||||
|
const silk = await fsPromise.readFile(inputFilePath)
|
||||||
|
const { data } = await decode(silk, 24000)
|
||||||
|
const tmpPath = path.join(TEMP_DIR, path.basename(inputFilePath))
|
||||||
|
const outFilePath = tmpPath + `.${outFormat}`
|
||||||
|
const pcmFilePath = tmpPath + '.pcm'
|
||||||
|
await fsPromise.writeFile(pcmFilePath, data)
|
||||||
|
return convert(pcmFilePath, {
|
||||||
|
input: [
|
||||||
|
'-f s16le',
|
||||||
|
'-ar 24000',
|
||||||
|
'-ac 1'
|
||||||
|
]
|
||||||
|
}, outFilePath)
|
||||||
|
}
|
@@ -1,13 +1,10 @@
|
|||||||
import fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import fsPromise from 'fs/promises'
|
import fsPromise from 'node:fs/promises'
|
||||||
import crypto from 'crypto'
|
|
||||||
import util from 'util'
|
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import { log, TEMP_DIR } from './index'
|
import { log, TEMP_DIR } from './index'
|
||||||
import { dbUtil } from '../db'
|
import { dbUtil } from '../db'
|
||||||
import * as fileType from 'file-type'
|
import * as fileType from 'file-type'
|
||||||
import { net } from 'electron'
|
import { randomUUID, createHash } from 'node:crypto'
|
||||||
|
|
||||||
export function isGIF(path: string) {
|
export function isGIF(path: string) {
|
||||||
const buffer = Buffer.alloc(4)
|
const buffer = Buffer.alloc(4)
|
||||||
@@ -37,7 +34,6 @@ export function checkFileReceived(path: string, timeout: number = 3000): Promise
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function file2base64(path: string) {
|
export async function file2base64(path: string) {
|
||||||
const readFile = util.promisify(fs.readFile)
|
|
||||||
let result = {
|
let result = {
|
||||||
err: '',
|
err: '',
|
||||||
data: '',
|
data: '',
|
||||||
@@ -53,10 +49,10 @@ export async function file2base64(path: string) {
|
|||||||
result.err = e.toString()
|
result.err = e.toString()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const data = await readFile(path)
|
const data = await fsPromise.readFile(path)
|
||||||
// 转换为Base64编码
|
// 转换为Base64编码
|
||||||
result.data = data.toString('base64')
|
result.data = data.toString('base64')
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
result.err = err.toString()
|
result.err = err.toString()
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -66,7 +62,7 @@ export function calculateFileMD5(filePath: string): Promise<string> {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 创建一个流式读取器
|
// 创建一个流式读取器
|
||||||
const stream = fs.createReadStream(filePath)
|
const stream = fs.createReadStream(filePath)
|
||||||
const hash = crypto.createHash('md5')
|
const hash = createHash('md5')
|
||||||
|
|
||||||
stream.on('data', (data: Buffer) => {
|
stream.on('data', (data: Buffer) => {
|
||||||
// 当读取到数据时,更新哈希对象的状态
|
// 当读取到数据时,更新哈希对象的状态
|
||||||
@@ -91,7 +87,6 @@ export interface HttpDownloadOptions {
|
|||||||
headers?: Record<string, string> | string
|
headers?: Record<string, string> | string
|
||||||
}
|
}
|
||||||
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
|
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
|
||||||
let chunks: Buffer[] = []
|
|
||||||
let url: string
|
let url: string
|
||||||
let headers: Record<string, string> = {
|
let headers: Record<string, string> = {
|
||||||
'User-Agent':
|
'User-Agent':
|
||||||
@@ -109,12 +104,10 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fetchRes = await net.fetch(url, {headers})
|
const fetchRes = await fetch(url, { headers })
|
||||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`)
|
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`)
|
||||||
|
|
||||||
const blob = await fetchRes.blob()
|
return Buffer.from(await fetchRes.arrayBuffer())
|
||||||
let buffer = await blob.arrayBuffer()
|
|
||||||
return Buffer.from(buffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Uri2LocalRes = {
|
type Uri2LocalRes = {
|
||||||
@@ -126,7 +119,7 @@ type Uri2LocalRes = {
|
|||||||
isLocal: boolean
|
isLocal: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function uri2local(uri: string, fileName: string = null): Promise<Uri2LocalRes> {
|
export async function uri2local(uri: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||||
let res = {
|
let res = {
|
||||||
success: false,
|
success: false,
|
||||||
errMsg: '',
|
errMsg: '',
|
||||||
@@ -136,13 +129,13 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
|
|||||||
isLocal: false,
|
isLocal: false,
|
||||||
}
|
}
|
||||||
if (!fileName) {
|
if (!fileName) {
|
||||||
fileName = uuidv4()
|
fileName = randomUUID()
|
||||||
}
|
}
|
||||||
let filePath = path.join(TEMP_DIR, fileName)
|
let filePath = path.join(TEMP_DIR, fileName)
|
||||||
let url = null
|
let url: URL | null = null
|
||||||
try {
|
try {
|
||||||
url = new URL(uri)
|
url = new URL(uri)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
res.errMsg = `uri ${uri} 解析失败,` + e.toString() + ` 可能${uri}不存在`
|
res.errMsg = `uri ${uri} 解析失败,` + e.toString() + ` 可能${uri}不存在`
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -153,17 +146,17 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
|
|||||||
let base64Data = uri.split('base64://')[1]
|
let base64Data = uri.split('base64://')[1]
|
||||||
try {
|
try {
|
||||||
const buffer = Buffer.from(base64Data, 'base64')
|
const buffer = Buffer.from(base64Data, 'base64')
|
||||||
fs.writeFileSync(filePath, buffer)
|
await fsPromise.writeFile(filePath, buffer)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
res.errMsg = `base64文件下载失败,` + e.toString()
|
res.errMsg = `base64文件下载失败,` + e.toString()
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
} else if (url.protocol == 'http:' || url.protocol == 'https:') {
|
} else if (url.protocol == 'http:' || url.protocol == 'https:') {
|
||||||
// 下载文件
|
// 下载文件
|
||||||
let buffer: Buffer = null
|
let buffer: Buffer | null = null
|
||||||
try {
|
try {
|
||||||
buffer = await httpDownload(uri)
|
buffer = await httpDownload(uri)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
res.errMsg = `${url}下载失败,` + e.toString()
|
res.errMsg = `${url}下载失败,` + e.toString()
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -178,8 +171,8 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
|
|||||||
}
|
}
|
||||||
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_')
|
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_')
|
||||||
res.fileName = fileName
|
res.fileName = fileName
|
||||||
filePath = path.join(TEMP_DIR, uuidv4() + fileName)
|
filePath = path.join(TEMP_DIR, randomUUID() + fileName)
|
||||||
fs.writeFileSync(filePath, buffer)
|
await fsPromise.writeFile(filePath, buffer)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
res.errMsg = `${url}下载失败,` + e.toString()
|
res.errMsg = `${url}下载失败,` + e.toString()
|
||||||
return res
|
return res
|
||||||
@@ -215,10 +208,10 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
|
|||||||
// }
|
// }
|
||||||
if (!res.isLocal && !res.ext) {
|
if (!res.isLocal && !res.ext) {
|
||||||
try {
|
try {
|
||||||
let ext: string = (await fileType.fileTypeFromFile(filePath)).ext
|
const ext = (await fileType.fileTypeFromFile(filePath))?.ext
|
||||||
if (ext) {
|
if (ext) {
|
||||||
log('获取文件类型', ext, filePath)
|
log('获取文件类型', ext, filePath)
|
||||||
fs.renameSync(filePath, filePath + `.${ext}`)
|
await fsPromise.rename(filePath, filePath + `.${ext}`)
|
||||||
filePath += `.${ext}`
|
filePath += `.${ext}`
|
||||||
res.fileName += `.${ext}`
|
res.fileName += `.${ext}`
|
||||||
res.ext = ext
|
res.ext = ext
|
||||||
|
@@ -41,7 +41,7 @@ export function mergeNewProperties(newObj: any, oldObj: any) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNull(value: any) {
|
export function isNull(value: unknown) {
|
||||||
return value === undefined || value === null
|
return value === undefined || value === null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,25 +73,51 @@ export function wrapText(str: string, maxLength: number): string {
|
|||||||
* @param customKey 自定义缓存键前缀,可为空,防止方法名参数名一致时导致缓存键冲突
|
* @param customKey 自定义缓存键前缀,可为空,防止方法名参数名一致时导致缓存键冲突
|
||||||
* @returns 处理后缓存或调用原方法的结果
|
* @returns 处理后缓存或调用原方法的结果
|
||||||
*/
|
*/
|
||||||
export function cacheFunc(ttl: number, customKey: string='') {
|
export function cacheFunc(ttl: number, customKey: string = '') {
|
||||||
const cache = new Map<string, { expiry: number; value: any }>();
|
const cache = new Map<string, { expiry: number; value: any }>()
|
||||||
|
|
||||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
|
||||||
const originalMethod = descriptor.value;
|
const originalMethod = descriptor.value
|
||||||
const className = target.constructor.name; // 获取类名
|
const className = target.constructor.name // 获取类名
|
||||||
const methodName = propertyKey; // 获取方法名
|
const methodName = propertyKey // 获取方法名
|
||||||
descriptor.value = async function (...args: any[]){
|
descriptor.value = async function (...args: any[]) {
|
||||||
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`;
|
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`
|
||||||
const cached = cache.get(cacheKey);
|
const cached = cache.get(cacheKey)
|
||||||
if (cached && cached.expiry > Date.now()) {
|
if (cached && cached.expiry > Date.now()) {
|
||||||
return cached.value;
|
return cached.value
|
||||||
} else {
|
} else {
|
||||||
const result = await originalMethod.apply(this, args);
|
const result = await originalMethod.apply(this, args)
|
||||||
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl });
|
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl })
|
||||||
return result;
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
return descriptor;
|
return descriptor
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CacheClassFuncAsyncExtend(ttl: number = 3600 * 1000, customKey: string = '', checker: any = (...data: any[]) => { return true }) {
|
||||||
|
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
||||||
|
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 result = await originalMethod.apply(this, args)
|
||||||
|
if (!checker(...args, result)) {
|
||||||
|
return result //丢弃缓存
|
||||||
|
}
|
||||||
|
cache.set(key, { expiry: Date.now() + ttl, value: result })
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return logExecutionTime
|
||||||
}
|
}
|
71
src/common/utils/table.ts
Normal file
71
src/common/utils/table.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
export class LimitedHashTable<K, V> {
|
||||||
|
private keyToValue: Map<K, V> = new Map()
|
||||||
|
private valueToKey: Map<V, K> = new Map()
|
||||||
|
private maxSize: number
|
||||||
|
|
||||||
|
constructor(maxSize: number) {
|
||||||
|
this.maxSize = maxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
resize(count: number) {
|
||||||
|
this.maxSize = count
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key: K, value: V): void {
|
||||||
|
this.keyToValue.set(key, value)
|
||||||
|
this.valueToKey.set(value, key)
|
||||||
|
while (this.keyToValue.size !== this.valueToKey.size) {
|
||||||
|
console.log('keyToValue.size !== valueToKey.size Error Atom')
|
||||||
|
this.keyToValue.clear()
|
||||||
|
this.valueToKey.clear()
|
||||||
|
}
|
||||||
|
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
||||||
|
const oldestKey = this.keyToValue.keys().next().value
|
||||||
|
this.valueToKey.delete(this.keyToValue.get(oldestKey)!)
|
||||||
|
this.keyToValue.delete(oldestKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(key: K): V | undefined {
|
||||||
|
return this.keyToValue.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
getKey(value: V): K | undefined {
|
||||||
|
return this.valueToKey.get(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteByValue(value: V): void {
|
||||||
|
const key = this.valueToKey.get(value)
|
||||||
|
if (key !== undefined) {
|
||||||
|
this.keyToValue.delete(key)
|
||||||
|
this.valueToKey.delete(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteByKey(key: K): void {
|
||||||
|
const value = this.keyToValue.get(key)
|
||||||
|
if (value !== undefined) {
|
||||||
|
this.keyToValue.delete(key)
|
||||||
|
this.valueToKey.delete(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getKeyList(): K[] {
|
||||||
|
return Array.from(this.keyToValue.keys())
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取最近刚写入的几个值
|
||||||
|
getHeads(size: number): { key: K; value: V }[] | undefined {
|
||||||
|
const keyList = this.getKeyList()
|
||||||
|
if (keyList.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const result: { key: K; value: V }[] = []
|
||||||
|
const listSize = Math.min(size, keyList.length)
|
||||||
|
for (let i = 0; i < listSize; i++) {
|
||||||
|
const key = keyList[listSize - i]
|
||||||
|
result.push({ key, value: this.keyToValue.get(key)! })
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@@ -91,7 +91,7 @@ export async function getRemoteVersionByMirror(mirrorGithub: string) {
|
|||||||
releasePage = (await httpDownload(mirrorGithub + '/LLOneBot/LLOneBot/releases')).toString()
|
releasePage = (await httpDownload(mirrorGithub + '/LLOneBot/LLOneBot/releases')).toString()
|
||||||
// log("releasePage", releasePage);
|
// log("releasePage", releasePage);
|
||||||
if (releasePage === 'error') return ''
|
if (releasePage === 'error') return ''
|
||||||
return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))[0]
|
return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))?.[0]
|
||||||
} catch {}
|
} catch {}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
@@ -31,10 +31,10 @@ export async function getVideoInfo(filePath: string) {
|
|||||||
console.log('未找到视频流信息。')
|
console.log('未找到视频流信息。')
|
||||||
}
|
}
|
||||||
resolve({
|
resolve({
|
||||||
width: videoStream.width,
|
width: videoStream?.width!,
|
||||||
height: videoStream.height,
|
height: videoStream?.height!,
|
||||||
time: parseInt(videoStream.duration),
|
time: parseInt(videoStream?.duration!),
|
||||||
format: metadata.format.format_name,
|
format: metadata.format.format_name!,
|
||||||
size,
|
size,
|
||||||
filePath,
|
filePath,
|
||||||
})
|
})
|
||||||
@@ -67,7 +67,7 @@ export async function encodeMp4(filePath: string) {
|
|||||||
return videoInfo
|
return videoInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkFfmpeg(newPath: string = null): Promise<boolean> {
|
export function checkFfmpeg(newPath: string | null = null): Promise<boolean> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
log('开始检查ffmpeg', newPath)
|
log('开始检查ffmpeg', newPath)
|
||||||
if (newPath) {
|
if (newPath) {
|
||||||
|
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@@ -3,6 +3,6 @@ import { type LLOneBot } from './preload'
|
|||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
llonebot: LLOneBot
|
llonebot: LLOneBot
|
||||||
LiteLoader: any
|
LiteLoader: Record<string, any>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
204
src/main/main.ts
204
src/main/main.ts
@@ -13,7 +13,7 @@ import {
|
|||||||
CHANNEL_UPDATE,
|
CHANNEL_UPDATE,
|
||||||
} from '../common/channels'
|
} from '../common/channels'
|
||||||
import { ob11WebsocketServer } from '../onebot11/server/ws/WebsocketServer'
|
import { ob11WebsocketServer } from '../onebot11/server/ws/WebsocketServer'
|
||||||
import { DATA_DIR } from '../common/utils'
|
import { DATA_DIR, qqPkgInfo } from '../common/utils'
|
||||||
import {
|
import {
|
||||||
friendRequests,
|
friendRequests,
|
||||||
getFriend,
|
getFriend,
|
||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
getGroupMember,
|
getGroupMember,
|
||||||
groups,
|
groups,
|
||||||
llonebotError,
|
llonebotError,
|
||||||
refreshGroupMembers,
|
|
||||||
selfInfo,
|
selfInfo,
|
||||||
uidMaps,
|
uidMaps,
|
||||||
} from '../common/data'
|
} from '../common/data'
|
||||||
@@ -36,11 +35,8 @@ import {
|
|||||||
RawMessage,
|
RawMessage,
|
||||||
} from '../ntqqapi/types'
|
} from '../ntqqapi/types'
|
||||||
import { httpHeart, ob11HTTPServer } from '../onebot11/server/http'
|
import { httpHeart, ob11HTTPServer } from '../onebot11/server/http'
|
||||||
import { OB11FriendRecallNoticeEvent } from '../onebot11/event/notice/OB11FriendRecallNoticeEvent'
|
|
||||||
import { OB11GroupRecallNoticeEvent } from '../onebot11/event/notice/OB11GroupRecallNoticeEvent'
|
|
||||||
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
||||||
import { ob11ReverseWebsockets } from '../onebot11/server/ws/ReverseWebsocket'
|
import { ob11ReverseWebsockets } from '../onebot11/server/ws/ReverseWebsocket'
|
||||||
import { OB11GroupAdminNoticeEvent } from '../onebot11/event/notice/OB11GroupAdminNoticeEvent'
|
|
||||||
import { OB11GroupRequestEvent } from '../onebot11/event/request/OB11GroupRequest'
|
import { OB11GroupRequestEvent } from '../onebot11/event/request/OB11GroupRequest'
|
||||||
import { OB11FriendRequestEvent } from '../onebot11/event/request/OB11FriendRequest'
|
import { OB11FriendRequestEvent } from '../onebot11/event/request/OB11FriendRequest'
|
||||||
import * as path from 'node:path'
|
import * as path from 'node:path'
|
||||||
@@ -48,16 +44,15 @@ import { dbUtil } from '../common/db'
|
|||||||
import { setConfig } from './setConfig'
|
import { setConfig } from './setConfig'
|
||||||
import { NTQQUserApi } from '../ntqqapi/api/user'
|
import { NTQQUserApi } from '../ntqqapi/api/user'
|
||||||
import { NTQQGroupApi } from '../ntqqapi/api/group'
|
import { NTQQGroupApi } from '../ntqqapi/api/group'
|
||||||
import { crychic } from '../ntqqapi/native/crychic'
|
|
||||||
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from '../onebot11/event/notice/OB11PokeEvent'
|
|
||||||
import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
|
import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
|
||||||
import { log } from '../common/utils/log'
|
import { log } from '../common/utils/log'
|
||||||
import { getConfigUtil } from '../common/config'
|
import { getConfigUtil } from '../common/config'
|
||||||
import { checkFfmpeg } from '../common/utils/video'
|
import { checkFfmpeg } from '../common/utils/video'
|
||||||
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
||||||
import '../ntqqapi/native/wrapper'
|
import '../ntqqapi/wrapper'
|
||||||
|
import { sentMessages } from '@/ntqqapi/api'
|
||||||
let running = false
|
import { NTEventDispatch } from '../common/utils/EventTask'
|
||||||
|
import { wrapperConstructor, getSession } from '../ntqqapi/wrapper'
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null
|
let mainWindow: BrowserWindow | null = null
|
||||||
|
|
||||||
@@ -127,7 +122,7 @@ function onLoad() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
dialog
|
dialog
|
||||||
.showMessageBox(mainWindow, {
|
.showMessageBox(mainWindow!, {
|
||||||
type: 'question',
|
type: 'question',
|
||||||
buttons: ['确认', '取消'],
|
buttons: ['确认', '取消'],
|
||||||
defaultId: 0, // 默认选中的按钮,0 代表第一个按钮,即 "确认"
|
defaultId: 0, // 默认选中的按钮,0 代表第一个按钮,即 "确认"
|
||||||
@@ -190,43 +185,41 @@ function onLoad() {
|
|||||||
postOb11Event(groupEvent)
|
postOb11Event(groupEvent)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => {
|
OB11Constructor.PrivateEvent(message).then((privateEvent) => {
|
||||||
if (friendAddEvent) {
|
log(message)
|
||||||
// log("post friend add event", friendAddEvent);
|
if (privateEvent) {
|
||||||
postOb11Event(friendAddEvent)
|
// log("post private event", privateEvent);
|
||||||
|
postOb11Event(privateEvent)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => {
|
||||||
|
// log(message)
|
||||||
|
// if (friendAddEvent) {
|
||||||
|
// // log("post friend add event", friendAddEvent);
|
||||||
|
// postOb11Event(friendAddEvent)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startReceiveHook() {
|
async function startReceiveHook() {
|
||||||
startHook().then()
|
startHook()
|
||||||
if (getConfigUtil().getConfig().enablePoke) {
|
|
||||||
crychic.loadNode()
|
|
||||||
crychic.registerPokeHandler((id, isGroup) => {
|
|
||||||
log(`收到戳一戳消息了!是否群聊:${isGroup},id:${id}`)
|
|
||||||
let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent
|
|
||||||
if (isGroup) {
|
|
||||||
pokeEvent = new OB11GroupPokeEvent(parseInt(id))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pokeEvent = new OB11FriendPokeEvent(parseInt(id))
|
|
||||||
}
|
|
||||||
postOb11Event(pokeEvent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
registerReceiveHook<{
|
registerReceiveHook<{
|
||||||
msgList: Array<RawMessage>
|
msgList: Array<RawMessage>
|
||||||
}>([ReceiveCmdS.NEW_MSG, ReceiveCmdS.NEW_ACTIVE_MSG], async (payload) => {
|
}>([ReceiveCmdS.NEW_MSG, ReceiveCmdS.NEW_ACTIVE_MSG], async (payload) => {
|
||||||
try {
|
try {
|
||||||
await postReceiveMsg(payload.msgList)
|
await postReceiveMsg(payload.msgList)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('report message error: ', e.stack.toString())
|
log('report message error: ', e.stack.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const recallMsgIds: string[] = [] // 避免重复上报
|
const recallMsgIds: string[] = [] // 避免重复上报
|
||||||
registerReceiveHook<{ msgList: Array<RawMessage> }>([ReceiveCmdS.UPDATE_MSG], async (payload) => {
|
registerReceiveHook<{ msgList: Array<RawMessage> }>([ReceiveCmdS.UPDATE_MSG], async (payload) => {
|
||||||
for (const message of payload.msgList) {
|
for (const message of payload.msgList) {
|
||||||
|
const sentMessage = sentMessages[message.msgId]
|
||||||
|
if (sentMessage) {
|
||||||
|
Object.assign(sentMessage, message)
|
||||||
|
}
|
||||||
log('message update', message.msgId, message)
|
log('message update', message.msgId, message)
|
||||||
if (message.recallTime != '0') {
|
if (message.recallTime != '0') {
|
||||||
if (recallMsgIds.includes(message.msgId)) {
|
if (recallMsgIds.includes(message.msgId)) {
|
||||||
@@ -260,7 +253,7 @@ function onLoad() {
|
|||||||
// log("reportSelfMessage", payload)
|
// log("reportSelfMessage", payload)
|
||||||
try {
|
try {
|
||||||
await postReceiveMsg([payload.msgRecord])
|
await postReceiveMsg([payload.msgRecord])
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('report self message error: ', e.stack.toString())
|
log('report self message error: ', e.stack.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -300,34 +293,36 @@ function onLoad() {
|
|||||||
// if (notify.user2.uid) {
|
// if (notify.user2.uid) {
|
||||||
// member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid);
|
// member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid);
|
||||||
// }
|
// }
|
||||||
if (
|
// 原本的群管变更通知事件处理
|
||||||
[GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(
|
// if (
|
||||||
notify.type,
|
// [GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(
|
||||||
)
|
// notify.type,
|
||||||
) {
|
// )
|
||||||
const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid)
|
// ) {
|
||||||
log('有管理员变动通知')
|
// const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid)
|
||||||
refreshGroupMembers(notify.group.groupCode).then()
|
// log('有管理员变动通知')
|
||||||
let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent()
|
// refreshGroupMembers(notify.group.groupCode).then()
|
||||||
groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode)
|
// let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent()
|
||||||
log('开始获取变动的管理员')
|
// groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode)
|
||||||
if (member1) {
|
// log('开始获取变动的管理员')
|
||||||
log('变动管理员获取成功')
|
// if (member1) {
|
||||||
groupAdminNoticeEvent.user_id = parseInt(member1.uin)
|
// log('变动管理员获取成功')
|
||||||
groupAdminNoticeEvent.sub_type = [
|
// groupAdminNoticeEvent.user_id = parseInt(member1.uin)
|
||||||
GroupNotifyTypes.ADMIN_UNSET,
|
// groupAdminNoticeEvent.sub_type = [
|
||||||
GroupNotifyTypes.ADMIN_UNSET_OTHER,
|
// GroupNotifyTypes.ADMIN_UNSET,
|
||||||
].includes(notify.type)
|
// GroupNotifyTypes.ADMIN_UNSET_OTHER,
|
||||||
? 'unset'
|
// ].includes(notify.type)
|
||||||
: 'set'
|
// ? 'unset'
|
||||||
// member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal;
|
// : 'set'
|
||||||
postOb11Event(groupAdminNoticeEvent, true)
|
// // member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal;
|
||||||
}
|
// postOb11Event(groupAdminNoticeEvent, true)
|
||||||
else {
|
// }
|
||||||
log('获取群通知的成员信息失败', notify, getGroup(notify.group.groupCode))
|
// else {
|
||||||
}
|
// log('获取群通知的成员信息失败', notify, getGroup(notify.group.groupCode))
|
||||||
}
|
// }
|
||||||
else if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) {
|
// }
|
||||||
|
// else
|
||||||
|
if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) {
|
||||||
log('有成员退出通知', notify)
|
log('有成员退出通知', notify)
|
||||||
try {
|
try {
|
||||||
const member1 = await NTQQUserApi.getUserDetailInfo(notify.user1.uid)
|
const member1 = await NTQQUserApi.getUserDetailInfo(notify.user1.uid)
|
||||||
@@ -336,7 +331,7 @@ function onLoad() {
|
|||||||
if (notify.user2.uid) {
|
if (notify.user2.uid) {
|
||||||
// 是被踢的
|
// 是被踢的
|
||||||
const member2 = await getGroupMember(notify.group.groupCode, notify.user2.uid)
|
const member2 = await getGroupMember(notify.group.groupCode, notify.user2.uid)
|
||||||
operatorId = member2.uin
|
operatorId = member2?.uin!
|
||||||
subType = 'kick'
|
subType = 'kick'
|
||||||
}
|
}
|
||||||
let groupDecreaseEvent = new OB11GroupDecreaseEvent(
|
let groupDecreaseEvent = new OB11GroupDecreaseEvent(
|
||||||
@@ -346,14 +341,12 @@ function onLoad() {
|
|||||||
subType,
|
subType,
|
||||||
)
|
)
|
||||||
postOb11Event(groupDecreaseEvent, true)
|
postOb11Event(groupDecreaseEvent, true)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('获取群通知的成员信息失败', notify, e.stack.toString())
|
log('获取群通知的成员信息失败', notify, e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ([GroupNotifyTypes.JOIN_REQUEST, GroupNotifyTypes.JOIN_REQUEST_BY_INVITED].includes(notify.type)) {
|
else if ([GroupNotifyTypes.JOIN_REQUEST, GroupNotifyTypes.JOIN_REQUEST_BY_INVITED].includes(notify.type)) {
|
||||||
log('有加群请求')
|
log('有加群请求')
|
||||||
let groupRequestEvent = new OB11GroupRequestEvent()
|
|
||||||
groupRequestEvent.group_id = parseInt(notify.group.groupCode)
|
|
||||||
let requestQQ = uidMaps[notify.user1.uid]
|
let requestQQ = uidMaps[notify.user1.uid]
|
||||||
if (!requestQQ) {
|
if (!requestQQ) {
|
||||||
try {
|
try {
|
||||||
@@ -362,40 +355,47 @@ function onLoad() {
|
|||||||
log('获取加群人QQ号失败', e)
|
log('获取加群人QQ号失败', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupRequestEvent.user_id = parseInt(requestQQ) || 0
|
let invitorId: number
|
||||||
groupRequestEvent.sub_type = 'add'
|
|
||||||
groupRequestEvent.comment = notify.postscript
|
|
||||||
groupRequestEvent.flag = notify.seq
|
|
||||||
if (notify.type == GroupNotifyTypes.JOIN_REQUEST_BY_INVITED) {
|
if (notify.type == GroupNotifyTypes.JOIN_REQUEST_BY_INVITED) {
|
||||||
// groupRequestEvent.sub_type = 'invite'
|
// groupRequestEvent.sub_type = 'invite'
|
||||||
let invitorQQ = uidMaps[notify.user2.uid]
|
let invitorQQ = uidMaps[notify.user2.uid]
|
||||||
if (!invitorQQ) {
|
if (!invitorQQ) {
|
||||||
try {
|
try {
|
||||||
let invitor = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))
|
let invitor = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))
|
||||||
groupRequestEvent.invitor_id = parseInt(invitor.uin)
|
invitorId = parseInt(invitor.uin)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
groupRequestEvent.invitor_id = 0
|
invitorId = 0
|
||||||
log('获取邀请人QQ号失败', e)
|
log('获取邀请人QQ号失败', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const groupRequestEvent = new OB11GroupRequestEvent(
|
||||||
|
parseInt(notify.group.groupCode),
|
||||||
|
parseInt(requestQQ) || 0,
|
||||||
|
notify.seq,
|
||||||
|
notify.postscript,
|
||||||
|
invitorId!,
|
||||||
|
'add'
|
||||||
|
)
|
||||||
postOb11Event(groupRequestEvent)
|
postOb11Event(groupRequestEvent)
|
||||||
}
|
}
|
||||||
else if (notify.type == GroupNotifyTypes.INVITE_ME) {
|
else if (notify.type == GroupNotifyTypes.INVITE_ME) {
|
||||||
log('收到邀请我加群通知')
|
log('收到邀请我加群通知')
|
||||||
let groupInviteEvent = new OB11GroupRequestEvent()
|
let userId = uidMaps[notify.user2.uid]
|
||||||
groupInviteEvent.group_id = parseInt(notify.group.groupCode)
|
if (!userId) {
|
||||||
let user_id = uidMaps[notify.user2.uid]
|
userId = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))?.uin
|
||||||
if (!user_id) {
|
|
||||||
user_id = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))?.uin
|
|
||||||
}
|
}
|
||||||
groupInviteEvent.user_id = parseInt(user_id)
|
const groupInviteEvent = new OB11GroupRequestEvent(
|
||||||
groupInviteEvent.sub_type = 'invite'
|
parseInt(notify.group.groupCode),
|
||||||
// groupInviteEvent.invitor_id = parseInt(user_id)
|
parseInt(userId),
|
||||||
groupInviteEvent.flag = notify.seq
|
notify.seq,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
'invite'
|
||||||
|
)
|
||||||
postOb11Event(groupInviteEvent)
|
postOb11Event(groupInviteEvent)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('解析群通知失败', e.stack.toString())
|
log('解析群通知失败', e.stack.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,19 +407,18 @@ function onLoad() {
|
|||||||
|
|
||||||
registerReceiveHook<FriendRequestNotify>(ReceiveCmdS.FRIEND_REQUEST, async (payload) => {
|
registerReceiveHook<FriendRequestNotify>(ReceiveCmdS.FRIEND_REQUEST, async (payload) => {
|
||||||
for (const req of payload.data.buddyReqs) {
|
for (const req of payload.data.buddyReqs) {
|
||||||
let flag = req.friendUid + req.reqTime
|
const flag = req.friendUid + req.reqTime
|
||||||
if (req.isUnread && parseInt(req.reqTime) > startTime / 1000) {
|
if (req.isUnread && parseInt(req.reqTime) > startTime / 1000) {
|
||||||
friendRequests[flag] = req
|
friendRequests[flag] = req
|
||||||
log('有新的好友请求', req)
|
log('有新的好友请求', req)
|
||||||
let friendRequestEvent = new OB11FriendRequestEvent()
|
let userId: number
|
||||||
try {
|
try {
|
||||||
let requester = await NTQQUserApi.getUserDetailInfo(req.friendUid)
|
const requester = await NTQQUserApi.getUserDetailInfo(req.friendUid)
|
||||||
friendRequestEvent.user_id = parseInt(requester.uin)
|
userId = parseInt(requester.uin)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('获取加好友者QQ号失败', e)
|
log('获取加好友者QQ号失败', e)
|
||||||
}
|
}
|
||||||
friendRequestEvent.flag = flag
|
const friendRequestEvent = new OB11FriendRequestEvent(userId!, req.extWords, flag)
|
||||||
friendRequestEvent.comment = req.extWords
|
|
||||||
postOb11Event(friendRequestEvent)
|
postOb11Event(friendRequestEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,6 +429,11 @@ function onLoad() {
|
|||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
log('llonebot pid', process.pid)
|
log('llonebot pid', process.pid)
|
||||||
|
const config = getConfigUtil().getConfig()
|
||||||
|
if (!config.enableLLOB) {
|
||||||
|
log('LLOneBot 开关设置为关闭,不启动LLOneBot')
|
||||||
|
return
|
||||||
|
}
|
||||||
llonebotError.otherError = ''
|
llonebotError.otherError = ''
|
||||||
startTime = Date.now()
|
startTime = Date.now()
|
||||||
dbUtil.getReceivedTempUinMap().then((m) => {
|
dbUtil.getReceivedTempUinMap().then((m) => {
|
||||||
@@ -437,34 +441,12 @@ function onLoad() {
|
|||||||
uidMaps[value] = key
|
uidMaps[value] = key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
try{
|
NTEventDispatch.init({ ListenerMap: wrapperConstructor, WrapperSession: getSession()! })
|
||||||
log('start get groups')
|
|
||||||
const _groups = await NTQQGroupApi.getGroups()
|
|
||||||
log('_groups', _groups)
|
|
||||||
await Promise.all(
|
|
||||||
_groups.map(async (group) => {
|
|
||||||
try {
|
|
||||||
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
|
||||||
group.members = members
|
|
||||||
groups.push(group)
|
|
||||||
} catch (e) {
|
|
||||||
log('获取群成员失败', e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
log('获取群列表失败', e)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
log('start activate group member info')
|
log('start activate group member info')
|
||||||
NTQQGroupApi.activateMemberInfoChange().then().catch(log)
|
NTQQGroupApi.activateMemberInfoChange().then().catch(log)
|
||||||
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
||||||
startReceiveHook().then()
|
startReceiveHook().then()
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const config = getConfigUtil().getConfig()
|
|
||||||
if (config.ob11.enableHttp) {
|
if (config.ob11.enableHttp) {
|
||||||
ob11HTTPServer.start(config.ob11.httpPort)
|
ob11HTTPServer.start(config.ob11.httpPort)
|
||||||
}
|
}
|
||||||
@@ -508,7 +490,7 @@ function onLoad() {
|
|||||||
selfInfo.nick = userInfo.nick
|
selfInfo.nick = userInfo.nick
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('get self nickname failed', e.stack)
|
log('get self nickname failed', e.stack)
|
||||||
}
|
}
|
||||||
if (getSelfNickCount < 10) {
|
if (getSelfNickCount < 10) {
|
||||||
@@ -536,7 +518,7 @@ function onBrowserWindowCreated(window: BrowserWindow) {
|
|||||||
try {
|
try {
|
||||||
hookNTQQApiCall(window)
|
hookNTQQApiCall(window)
|
||||||
hookNTQQApiReceive(window)
|
hookNTQQApiReceive(window)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('LLOneBot hook error: ', e.toString())
|
log('LLOneBot hook error: ', e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,15 +10,25 @@ import {
|
|||||||
ElementType,
|
ElementType,
|
||||||
IMAGE_HTTP_HOST,
|
IMAGE_HTTP_HOST,
|
||||||
IMAGE_HTTP_HOST_NT, PicElement,
|
IMAGE_HTTP_HOST_NT, PicElement,
|
||||||
RawMessage,
|
|
||||||
} from '../types'
|
} from '../types'
|
||||||
import path from 'path'
|
import path from 'node:path'
|
||||||
import fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { log } from '@/common/utils'
|
import { log } from '@/common/utils'
|
||||||
import { rkeyManager } from '@/ntqqapi/api/rkey'
|
import { rkeyManager } from '@/ntqqapi/api/rkey'
|
||||||
|
import { getSession } from '@/ntqqapi/wrapper'
|
||||||
|
import { Peer } from '@/ntqqapi/types/msg'
|
||||||
|
|
||||||
export class NTQQFileApi {
|
export class NTQQFileApi {
|
||||||
|
static async getVideoUrl(peer: Peer, msgId: string, elementId: string): Promise<string> {
|
||||||
|
const session = getSession()
|
||||||
|
return (await session?.getRichMediaService().getVideoPlayUrlV2(peer,
|
||||||
|
msgId,
|
||||||
|
elementId,
|
||||||
|
0,
|
||||||
|
{ downSourceType: 1, triggerType: 1 })).urlResult?.domainUrl[0]?.url;
|
||||||
|
}
|
||||||
|
|
||||||
static async getFileType(filePath: string) {
|
static async getFileType(filePath: string) {
|
||||||
return await callNTQQApi<{ ext: string }>({
|
return await callNTQQApi<{ ext: string }>({
|
||||||
className: NTQQApiClass.FS_API,
|
className: NTQQApiClass.FS_API,
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
import { Friend, FriendRequest } from '../types'
|
import { Friend, FriendRequest, FriendV2 } from '../types'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
||||||
import { friendRequests } from '../../common/data'
|
import { friendRequests } from '@/common/data'
|
||||||
import { log } from '../../common/utils'
|
import { getSession } from '@/ntqqapi/wrapper'
|
||||||
|
import { BuddyListReqType, NodeIKernelProfileService } from '../services'
|
||||||
|
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||||
|
import { CacheClassFuncAsyncExtend } from '@/common/utils/helper'
|
||||||
|
import { LimitedHashTable } from '@/common/utils/table'
|
||||||
|
|
||||||
export class NTQQFriendApi {
|
export class NTQQFriendApi {
|
||||||
static async getFriends(forced = false) {
|
static async getFriends(forced = false) {
|
||||||
@@ -26,6 +30,7 @@ export class NTQQFriendApi {
|
|||||||
}
|
}
|
||||||
return _friends
|
return _friends
|
||||||
}
|
}
|
||||||
|
|
||||||
static async likeFriend(uid: string, count = 1) {
|
static async likeFriend(uid: string, count = 1) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.LIKE_FRIEND,
|
methodName: NTQQApiMethod.LIKE_FRIEND,
|
||||||
@@ -42,6 +47,7 @@ export class NTQQFriendApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleFriendRequest(flag: string, accept: boolean) {
|
static async handleFriendRequest(flag: string, accept: boolean) {
|
||||||
const request: FriendRequest = friendRequests[flag]
|
const request: FriendRequest = friendRequests[flag]
|
||||||
if (!request) {
|
if (!request) {
|
||||||
@@ -62,4 +68,43 @@ export class NTQQFriendApi {
|
|||||||
delete friendRequests[flag]
|
delete friendRequests[flag]
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||||
|
const uids: string[] = []
|
||||||
|
const session = getSession()
|
||||||
|
const buddyService = session?.getBuddyService()
|
||||||
|
const buddyListV2 = refresh ? await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL)
|
||||||
|
uids.push(...buddyListV2?.data.flatMap(item => item.buddyUids)!)
|
||||||
|
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||||
|
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||||
|
)
|
||||||
|
return Array.from(data.values())
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheClassFuncAsyncExtend(3600 * 1000, 'getBuddyIdMap', () => true)
|
||||||
|
static async getBuddyIdMapCache(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||||
|
return await NTQQFriendApi.getBuddyIdMap(refresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||||
|
const uids: string[] = []
|
||||||
|
const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000)
|
||||||
|
const session = getSession()
|
||||||
|
const buddyService = session?.getBuddyService()
|
||||||
|
const buddyListV2 = refresh ? await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL)
|
||||||
|
uids.push(...buddyListV2?.data.flatMap(item => item.buddyUids)!)
|
||||||
|
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||||
|
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||||
|
);
|
||||||
|
data.forEach((value, key) => {
|
||||||
|
retMap.set(value.uin!, value.uid!)
|
||||||
|
})
|
||||||
|
//console.log('getBuddyIdMap', retMap.getValue)
|
||||||
|
return retMap
|
||||||
|
}
|
||||||
|
|
||||||
|
static async isBuddy(uid: string): Promise<boolean> {
|
||||||
|
const session = getSession()
|
||||||
|
return session?.getBuddyService().isBuddy(uid)!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,24 +5,26 @@ import { deleteGroup, uidMaps } from '../../common/data'
|
|||||||
import { dbUtil } from '../../common/db'
|
import { dbUtil } from '../../common/db'
|
||||||
import { log } from '../../common/utils/log'
|
import { log } from '../../common/utils/log'
|
||||||
import { NTQQWindowApi, NTQQWindows } from './window'
|
import { NTQQWindowApi, NTQQWindows } from './window'
|
||||||
|
import { getSession } from '../wrapper'
|
||||||
|
|
||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
|
static async activateMemberListChange() {
|
||||||
static async activateMemberListChange(){
|
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.ACTIVATE_MEMBER_LIST_CHANGE,
|
methodName: NTQQApiMethod.ACTIVATE_MEMBER_LIST_CHANGE,
|
||||||
classNameIsRegister: true,
|
classNameIsRegister: true,
|
||||||
args: [],
|
args: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async activateMemberInfoChange(){
|
|
||||||
|
static async activateMemberInfoChange() {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.ACTIVATE_MEMBER_INFO_CHANGE,
|
methodName: NTQQApiMethod.ACTIVATE_MEMBER_INFO_CHANGE,
|
||||||
classNameIsRegister: true,
|
classNameIsRegister: true,
|
||||||
args: [],
|
args: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async getGroupAllInfo(groupCode: string, source: number=4){
|
|
||||||
|
static async getGroupAllInfo(groupCode: string, source: number = 4) {
|
||||||
return await callNTQQApi<GeneralCallResult & Group>({
|
return await callNTQQApi<GeneralCallResult & Group>({
|
||||||
methodName: NTQQApiMethod.GET_GROUP_ALL_INFO,
|
methodName: NTQQApiMethod.GET_GROUP_ALL_INFO,
|
||||||
args: [
|
args: [
|
||||||
@@ -34,6 +36,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroups(forced = false) {
|
static async getGroups(forced = false) {
|
||||||
// let cbCmd = ReceiveCmdS.GROUPS
|
// let cbCmd = ReceiveCmdS.GROUPS
|
||||||
// if (process.platform != 'win32') {
|
// if (process.platform != 'win32') {
|
||||||
@@ -51,47 +54,19 @@ export class NTQQGroupApi {
|
|||||||
log('get groups result', result)
|
log('get groups result', result)
|
||||||
return result.groupList
|
return result.groupList
|
||||||
}
|
}
|
||||||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
|
|
||||||
const sceneId = await callNTQQApi({
|
|
||||||
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
groupCode: groupQQ,
|
|
||||||
scene: 'groupMemberList_MainWindow',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
// log("get group member sceneId", sceneId);
|
|
||||||
try {
|
|
||||||
const result = await callNTQQApi<{
|
|
||||||
result: { infos: any }
|
|
||||||
}>({
|
|
||||||
methodName: NTQQApiMethod.GROUP_MEMBERS,
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
sceneId: sceneId,
|
|
||||||
num: num,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
|
||||||
const values = result.result.infos.values()
|
|
||||||
|
|
||||||
const members: GroupMember[] = Array.from(values)
|
static async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||||
for (const member of members) {
|
const session = getSession()
|
||||||
uidMaps[member.uid] = member.uin
|
const groupService = session?.getGroupService()
|
||||||
|
const sceneId = groupService?.createMemberListScene(groupQQ, 'groupMemberList_MainWindow')
|
||||||
|
const result = await groupService?.getNextMemberList(sceneId!, undefined, num)
|
||||||
|
if (result?.errCode !== 0) {
|
||||||
|
throw ('获取群成员列表出错,' + result?.errMsg)
|
||||||
}
|
}
|
||||||
// log(uidMaps);
|
return result.result.infos
|
||||||
// log("members info", values);
|
|
||||||
log(`get group ${groupQQ} members success`)
|
|
||||||
return members
|
|
||||||
} catch (e) {
|
|
||||||
log(`get group ${groupQQ} members failed`, e)
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
static async getGroupMembersInfo(groupCode: string, uids: string[], forceUpdate: boolean=false) {
|
static async getGroupMembersInfo(groupCode: string, uids: string[], forceUpdate: boolean = false) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.GROUP_MEMBERS_INFO,
|
methodName: NTQQApiMethod.GROUP_MEMBERS_INFO,
|
||||||
args: [
|
args: [
|
||||||
@@ -104,6 +79,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupNotifies() {
|
static async getGroupNotifies() {
|
||||||
// 获取管理员变更
|
// 获取管理员变更
|
||||||
// 加群通知,退出通知,需要管理员权限
|
// 加群通知,退出通知,需要管理员权限
|
||||||
@@ -118,6 +94,7 @@ export class NTQQGroupApi {
|
|||||||
args: [{ doubt: false, startSeq: '', number: 14 }, null],
|
args: [{ doubt: false, startSeq: '', number: 14 }, null],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupIgnoreNotifies() {
|
static async getGroupIgnoreNotifies() {
|
||||||
await NTQQGroupApi.getGroupNotifies()
|
await NTQQGroupApi.getGroupNotifies()
|
||||||
return await NTQQWindowApi.openWindow<GeneralCallResult & GroupNotifies>(
|
return await NTQQWindowApi.openWindow<GeneralCallResult & GroupNotifies>(
|
||||||
@@ -126,12 +103,13 @@ export class NTQQGroupApi {
|
|||||||
ReceiveCmdS.GROUP_NOTIFY,
|
ReceiveCmdS.GROUP_NOTIFY,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
||||||
const notify: GroupNotify = await dbUtil.getGroupNotify(seq)
|
const notify = await dbUtil.getGroupNotify(seq)
|
||||||
if (!notify) {
|
if (!notify) {
|
||||||
throw `${seq}对应的加群通知不存在`
|
throw `${seq}对应的加群通知不存在`
|
||||||
}
|
}
|
||||||
// delete groupNotifies[seq];
|
// delete groupNotifies[seq]
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.HANDLE_GROUP_REQUEST,
|
methodName: NTQQApiMethod.HANDLE_GROUP_REQUEST,
|
||||||
args: [
|
args: [
|
||||||
@@ -151,6 +129,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async quitGroup(groupQQ: string) {
|
static async quitGroup(groupQQ: string) {
|
||||||
const result = await callNTQQApi<GeneralCallResult>({
|
const result = await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.QUIT_GROUP,
|
methodName: NTQQApiMethod.QUIT_GROUP,
|
||||||
@@ -161,6 +140,7 @@ export class NTQQGroupApi {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
static async kickMember(
|
static async kickMember(
|
||||||
groupQQ: string,
|
groupQQ: string,
|
||||||
kickUids: string[],
|
kickUids: string[],
|
||||||
@@ -179,7 +159,8 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async banMember(groupQQ: string, memList: Array<{ uid: string; timeStamp: number }>) {
|
|
||||||
|
static async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
||||||
// timeStamp为秒数, 0为解除禁言
|
// timeStamp为秒数, 0为解除禁言
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.MUTE_MEMBER,
|
methodName: NTQQApiMethod.MUTE_MEMBER,
|
||||||
@@ -191,6 +172,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async banGroup(groupQQ: string, shutUp: boolean) {
|
static async banGroup(groupQQ: string, shutUp: boolean) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.MUTE_GROUP,
|
methodName: NTQQApiMethod.MUTE_GROUP,
|
||||||
@@ -203,6 +185,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
||||||
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
||||||
const res = await callNTQQApi<GeneralCallResult>({
|
const res = await callNTQQApi<GeneralCallResult>({
|
||||||
@@ -217,8 +200,9 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
NTQQGroupApi.getGroupMembersInfo(groupQQ, [memberUid], true).then().catch(log)
|
NTQQGroupApi.getGroupMembersInfo(groupQQ, [memberUid], true).then().catch(log)
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
|
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
|
||||||
@@ -232,6 +216,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setGroupName(groupQQ: string, groupName: string) {
|
static async setGroupName(groupQQ: string, groupName: string) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
||||||
@@ -281,5 +266,34 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static publishGroupBulletin(groupQQ: string, title: string, content: string) {}
|
|
||||||
|
static publishGroupBulletin(groupQQ: string, title: string, content: string) { }
|
||||||
|
|
||||||
|
static async removeGroupEssence(GroupCode: string, msgId: string) {
|
||||||
|
const session = getSession()
|
||||||
|
// 代码没测过
|
||||||
|
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||||
|
let MsgData = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||||
|
let param = {
|
||||||
|
groupCode: GroupCode,
|
||||||
|
msgRandom: parseInt(MsgData?.msgList[0].msgRandom!),
|
||||||
|
msgSeq: parseInt(MsgData?.msgList[0].msgSeq!)
|
||||||
|
}
|
||||||
|
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||||
|
return session?.getGroupService().removeGroupEssence(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async addGroupEssence(GroupCode: string, msgId: string) {
|
||||||
|
const session = getSession()
|
||||||
|
// 代码没测过
|
||||||
|
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||||
|
let MsgData = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||||
|
let param = {
|
||||||
|
groupCode: GroupCode,
|
||||||
|
msgRandom: parseInt(MsgData?.msgList[0].msgRandom!),
|
||||||
|
msgSeq: parseInt(MsgData?.msgList[0].msgSeq!)
|
||||||
|
}
|
||||||
|
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||||
|
return session?.getGroupService().addGroupEssence(param)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,17 @@
|
|||||||
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
||||||
import { ChatType, RawMessage, SendMessageElement } from '../types'
|
import { ChatType, RawMessage, SendMessageElement, Peer } from '../types'
|
||||||
import { dbUtil } from '../../common/db'
|
import { dbUtil } from '../../common/db'
|
||||||
import { selfInfo } from '../../common/data'
|
import { selfInfo } from '../../common/data'
|
||||||
import { ReceiveCmdS, registerReceiveHook } from '../hook'
|
import { ReceiveCmdS, registerReceiveHook } from '../hook'
|
||||||
import { log } from '../../common/utils/log'
|
import { log } from '../../common/utils/log'
|
||||||
import { sleep } from '../../common/utils/helper'
|
import { sleep } from '../../common/utils/helper'
|
||||||
import { isQQ998 } from '../../common/utils'
|
import { isQQ998, getBuildVersion } from '../../common/utils'
|
||||||
|
import { getSession } from '@/ntqqapi/wrapper'
|
||||||
|
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||||
|
|
||||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunnc
|
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
|
||||||
|
|
||||||
export interface Peer {
|
export let sentMessages: Record<string, RawMessage> = {} // msgId: RawMessage
|
||||||
chatType: ChatType
|
|
||||||
peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
|
||||||
guildId?: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendWaiter(peer: Peer, waitComplete = true, timeout: number = 10000) {
|
async function sendWaiter(peer: Peer, waitComplete = true, timeout: number = 10000) {
|
||||||
// 等待上一个相同的peer发送完
|
// 等待上一个相同的peer发送完
|
||||||
@@ -36,21 +34,24 @@ async function sendWaiter(peer: Peer, waitComplete = true, timeout: number = 100
|
|||||||
}
|
}
|
||||||
await waitLastSend()
|
await waitLastSend()
|
||||||
|
|
||||||
let sentMessage: RawMessage = null
|
let sentMessage: RawMessage | null = null
|
||||||
sendMessagePool[peerUid] = async (rawMessage: RawMessage) => {
|
sendMessagePool[peerUid] = async (rawMessage: RawMessage) => {
|
||||||
delete sendMessagePool[peerUid]
|
delete sendMessagePool[peerUid]
|
||||||
sentMessage = rawMessage
|
sentMessage = rawMessage
|
||||||
|
sentMessages[rawMessage.msgId] = rawMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
let checkSendCompleteUsingTime = 0
|
let checkSendCompleteUsingTime = 0
|
||||||
const checkSendComplete = async (): Promise<RawMessage> => {
|
const checkSendComplete = async (): Promise<RawMessage> => {
|
||||||
if (sentMessage) {
|
if (sentMessage) {
|
||||||
if (waitComplete) {
|
if (waitComplete) {
|
||||||
if ((await dbUtil.getMsgByLongId(sentMessage.msgId)).sendStatus == 2) {
|
if (sentMessage.sendStatus == 2) {
|
||||||
|
delete sentMessages[sentMessage.msgId]
|
||||||
return sentMessage
|
return sentMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
delete sentMessages[sentMessage.msgId]
|
||||||
return sentMessage
|
return sentMessage
|
||||||
}
|
}
|
||||||
// log(`给${peerUid}发送消息成功`)
|
// log(`给${peerUid}发送消息成功`)
|
||||||
@@ -202,6 +203,9 @@ export class NTQQMsgApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
|
if (getBuildVersion() >= 26702) {
|
||||||
|
return NTQQMsgApi.sendMsgV2(peer, msgElements, waitComplete, timeout)
|
||||||
|
}
|
||||||
const waiter = sendWaiter(peer, waitComplete, timeout)
|
const waiter = sendWaiter(peer, waitComplete, timeout)
|
||||||
callNTQQApi({
|
callNTQQApi({
|
||||||
methodName: NTQQApiMethod.SEND_MSG,
|
methodName: NTQQApiMethod.SEND_MSG,
|
||||||
@@ -218,6 +222,72 @@ export class NTQQMsgApi {
|
|||||||
return await waiter
|
return await waiter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
|
if (peer.chatType === ChatType.temp) {
|
||||||
|
//await NTQQMsgApi.PrepareTempChat().then().catch()
|
||||||
|
}
|
||||||
|
function generateMsgId() {
|
||||||
|
const timestamp = Math.floor(Date.now() / 1000)
|
||||||
|
const random = Math.floor(Math.random() * Math.pow(2, 32))
|
||||||
|
const buffer = Buffer.alloc(8)
|
||||||
|
buffer.writeUInt32BE(timestamp, 0)
|
||||||
|
buffer.writeUInt32BE(random, 4)
|
||||||
|
const msgId = BigInt('0x' + buffer.toString('hex')).toString()
|
||||||
|
return msgId
|
||||||
|
}
|
||||||
|
// 此处有采用Hack方法 利用数据返回正确得到对应消息
|
||||||
|
// 与之前 Peer队列 MsgSeq队列 真正的MsgId并发不同
|
||||||
|
// 谨慎采用 目前测试暂无问题 Developer.Mlikiowa
|
||||||
|
let msgId: string
|
||||||
|
try {
|
||||||
|
msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime())
|
||||||
|
} catch (error) {
|
||||||
|
//if (!napCatCore.session.getMsgService()['generateMsgUniqueId'])
|
||||||
|
//兜底识别策略V2
|
||||||
|
msgId = generateMsgId().toString()
|
||||||
|
}
|
||||||
|
let data = await NTEventDispatch.CallNormalEvent<
|
||||||
|
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
||||||
|
(msgList: RawMessage[]) => void
|
||||||
|
>(
|
||||||
|
'NodeIKernelMsgService/sendMsg',
|
||||||
|
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||||
|
1,
|
||||||
|
timeout,
|
||||||
|
(msgRecords: RawMessage[]) => {
|
||||||
|
for (let msgRecord of msgRecords) {
|
||||||
|
if (msgRecord.msgId === msgId && msgRecord.sendStatus === 2) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
msgId,
|
||||||
|
peer,
|
||||||
|
msgElements,
|
||||||
|
new Map()
|
||||||
|
)
|
||||||
|
const retMsg = data[1].find(msgRecord => {
|
||||||
|
if (msgRecord.msgId === msgId) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return retMsg!
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getMsgUnique(chatType: number, time: string) {
|
||||||
|
const session = getSession()
|
||||||
|
if (getBuildVersion() >= 26702) {
|
||||||
|
return session?.getMsgService().generateMsgUniqueId(chatType, time)!
|
||||||
|
}
|
||||||
|
return session?.getMsgService().getMsgUniqueId(time)!
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getServerTime() {
|
||||||
|
const session = getSession()
|
||||||
|
return session?.getMSFService().getServerTime()!
|
||||||
|
}
|
||||||
|
|
||||||
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||||
const waiter = sendWaiter(destPeer, true, 10000)
|
const waiter = sendWaiter(destPeer, true, 10000)
|
||||||
callNTQQApi<GeneralCallResult>({
|
callNTQQApi<GeneralCallResult>({
|
||||||
@@ -288,4 +358,8 @@ export class NTQQMsgApi {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||||
|
const session = getSession()
|
||||||
|
return await session?.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,58 +2,63 @@
|
|||||||
|
|
||||||
import { log } from '@/common/utils'
|
import { log } from '@/common/utils'
|
||||||
|
|
||||||
interface ServerRkeyData{
|
interface ServerRkeyData {
|
||||||
group_rkey: string;
|
group_rkey: string
|
||||||
private_rkey: string;
|
private_rkey: string
|
||||||
expired_time: number;
|
expired_time: number
|
||||||
}
|
}
|
||||||
|
|
||||||
class RkeyManager {
|
class RkeyManager {
|
||||||
serverUrl: string = '';
|
serverUrl: string = ''
|
||||||
private rkeyData: ServerRkeyData = {
|
private rkeyData: ServerRkeyData = {
|
||||||
group_rkey: '',
|
group_rkey: '',
|
||||||
private_rkey: '',
|
private_rkey: '',
|
||||||
expired_time: 0
|
expired_time: 0
|
||||||
};
|
|
||||||
constructor(serverUrl: string) {
|
|
||||||
this.serverUrl = serverUrl;
|
|
||||||
}
|
}
|
||||||
async getRkey(){
|
|
||||||
|
constructor(serverUrl: string) {
|
||||||
|
this.serverUrl = serverUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRkey() {
|
||||||
if (this.isExpired()) {
|
if (this.isExpired()) {
|
||||||
try {
|
try {
|
||||||
await this.refreshRkey();
|
await this.refreshRkey()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('获取rkey失败', e);
|
log('获取rkey失败', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.rkeyData;
|
return this.rkeyData
|
||||||
}
|
}
|
||||||
|
|
||||||
isExpired(): boolean {
|
isExpired(): boolean {
|
||||||
const now = new Date().getTime() / 1000;
|
const now = new Date().getTime() / 1000
|
||||||
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`);
|
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`)
|
||||||
return now > this.rkeyData.expired_time;
|
return now > this.rkeyData.expired_time
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshRkey(): Promise<any> {
|
async refreshRkey(): Promise<any> {
|
||||||
//刷新rkey
|
//刷新rkey
|
||||||
this.rkeyData = await this.fetchServerRkey();
|
this.rkeyData = await this.fetchServerRkey()
|
||||||
}
|
}
|
||||||
async fetchServerRkey(){
|
|
||||||
|
async fetchServerRkey() {
|
||||||
return new Promise<ServerRkeyData>((resolve, reject) => {
|
return new Promise<ServerRkeyData>((resolve, reject) => {
|
||||||
fetch(this.serverUrl)
|
fetch(this.serverUrl)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return reject(response.statusText); // 请求失败,返回错误信息
|
return reject(response.statusText) // 请求失败,返回错误信息
|
||||||
}
|
}
|
||||||
return response.json(); // 解析 JSON 格式的响应体
|
return response.json() // 解析 JSON 格式的响应体
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
resolve(data);
|
resolve(data)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
reject(error)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey');
|
|
||||||
|
export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey')
|
||||||
|
@@ -1,20 +1,22 @@
|
|||||||
import { callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod } from '../ntcall'
|
import { callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod } from '../ntcall'
|
||||||
import { Group, SelfInfo, User } from '../types'
|
import { SelfInfo, User, UserDetailInfoByUin, UserDetailInfoByUinV2 } from '../types'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { selfInfo, uidMaps } from '../../common/data'
|
import { selfInfo, uidMaps, friends, groupMembers } from '@/common/data'
|
||||||
import { NTQQWindowApi, NTQQWindows } from './window'
|
import { cacheFunc, isQQ998, log, sleep, getBuildVersion } from '@/common/utils'
|
||||||
import { cacheFunc, isQQ998, log, sleep } from '../../common/utils'
|
import { getSession } from '@/ntqqapi/wrapper'
|
||||||
import { wrapperApi } from '@/ntqqapi/native/wrapper'
|
|
||||||
import * as https from 'https'
|
|
||||||
import { RequestUtil } from '@/common/utils/request'
|
import { RequestUtil } from '@/common/utils/request'
|
||||||
|
import { NodeIKernelProfileService, UserDetailSource, ProfileBizType } from '../services'
|
||||||
|
import { NodeIKernelProfileListener } from '../listeners'
|
||||||
|
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||||
|
import { NTQQFriendApi } from './friend'
|
||||||
|
|
||||||
let userInfoCache: Record<string, User> = {} // uid: User
|
const userInfoCache: Record<string, User> = {} // uid: User
|
||||||
|
|
||||||
export interface ClientKeyData extends GeneralCallResult {
|
export interface ClientKeyData extends GeneralCallResult {
|
||||||
url: string;
|
url: string
|
||||||
keyIndex: string;
|
keyIndex: string
|
||||||
clientKey: string;
|
clientKey: string
|
||||||
expireTime: string;
|
expireTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NTQQUserApi {
|
export class NTQQUserApi {
|
||||||
@@ -48,8 +50,49 @@ export class NTQQUserApi {
|
|||||||
return result.profiles.get(uid)
|
return result.profiles.get(uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 26702 */
|
||||||
|
static async fetchUserDetailInfo(uid: string) {
|
||||||
|
type EventService = NodeIKernelProfileService['fetchUserDetailInfo']
|
||||||
|
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged']
|
||||||
|
const [_retData, profile] = await NTEventDispatch.CallNormalEvent
|
||||||
|
<EventService, EventListener>
|
||||||
|
(
|
||||||
|
'NodeIKernelProfileService/fetchUserDetailInfo',
|
||||||
|
'NodeIKernelProfileListener/onUserDetailInfoChanged',
|
||||||
|
1,
|
||||||
|
5000,
|
||||||
|
(profile) => {
|
||||||
|
if (profile.uid === uid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
'BuddyProfileStore',
|
||||||
|
[
|
||||||
|
uid
|
||||||
|
],
|
||||||
|
UserDetailSource.KSERVER,
|
||||||
|
[
|
||||||
|
ProfileBizType.KALL
|
||||||
|
]
|
||||||
|
)
|
||||||
|
const RetUser: User = {
|
||||||
|
...profile.simpleInfo.coreInfo,
|
||||||
|
...profile.simpleInfo.status,
|
||||||
|
...profile.simpleInfo.vasInfo,
|
||||||
|
...profile.commonExt,
|
||||||
|
...profile.simpleInfo.baseInfo,
|
||||||
|
qqLevel: profile.commonExt.qqLevel,
|
||||||
|
pendantId: ''
|
||||||
|
}
|
||||||
|
return RetUser
|
||||||
|
}
|
||||||
|
|
||||||
static async getUserDetailInfo(uid: string, getLevel = false, withBizInfo = true) {
|
static async getUserDetailInfo(uid: string, getLevel = false, withBizInfo = true) {
|
||||||
// this.getUserInfo(uid);
|
if (getBuildVersion() >= 26702) {
|
||||||
|
return this.fetchUserDetailInfo(uid)
|
||||||
|
}
|
||||||
|
// this.getUserInfo(uid)
|
||||||
let methodName = !isQQ998 ? NTQQApiMethod.USER_DETAIL_INFO : NTQQApiMethod.USER_DETAIL_INFO_WITH_BIZ_INFO
|
let methodName = !isQQ998 ? NTQQApiMethod.USER_DETAIL_INFO : NTQQApiMethod.USER_DETAIL_INFO_WITH_BIZ_INFO
|
||||||
if (!withBizInfo) {
|
if (!withBizInfo) {
|
||||||
methodName = NTQQApiMethod.USER_DETAIL_INFO
|
methodName = NTQQApiMethod.USER_DETAIL_INFO
|
||||||
@@ -82,7 +125,7 @@ export class NTQQUserApi {
|
|||||||
await fetchInfo()
|
await fetchInfo()
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
}
|
}
|
||||||
let userInfo = await fetchInfo()
|
const userInfo = await fetchInfo()
|
||||||
userInfoCache[uid] = userInfo
|
userInfoCache[uid] = userInfo
|
||||||
return userInfo
|
return userInfo
|
||||||
}
|
}
|
||||||
@@ -99,16 +142,17 @@ export class NTQQUserApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getQzoneCookies() {
|
static async getQzoneCookies() {
|
||||||
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + (await this.getClientKey()).clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + selfInfo.uin + '%2Finfocenter&keyindex=19%27'
|
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + (await this.getClientKey()).clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + selfInfo.uin + '%2Finfocenter&keyindex=19%27'
|
||||||
let cookies: { [key: string]: string; } = {};
|
let cookies: { [key: string]: string } = {}
|
||||||
try {
|
try {
|
||||||
cookies = await RequestUtil.HttpsGetCookies(requestUrl);
|
cookies = await RequestUtil.HttpsGetCookies(requestUrl)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
log('获取QZone Cookies失败', e)
|
log('获取QZone Cookies失败', e)
|
||||||
cookies = {}
|
cookies = {}
|
||||||
}
|
}
|
||||||
return cookies;
|
return cookies
|
||||||
}
|
}
|
||||||
static async getSkey(): Promise<string> {
|
static async getSkey(): Promise<string> {
|
||||||
const clientKeyData = await this.getClientKey()
|
const clientKeyData = await this.getClientKey()
|
||||||
@@ -117,24 +161,24 @@ export class NTQQUserApi {
|
|||||||
}
|
}
|
||||||
const url = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin
|
const url = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin
|
||||||
+ '&clientkey=' + clientKeyData.clientKey
|
+ '&clientkey=' + clientKeyData.clientKey
|
||||||
+ '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=' + clientKeyData.keyIndex;
|
+ '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=' + clientKeyData.keyIndex
|
||||||
return (await RequestUtil.HttpsGetCookies(url))?.skey;
|
return (await RequestUtil.HttpsGetCookies(url))?.skey
|
||||||
}
|
}
|
||||||
|
|
||||||
@cacheFunc(60 * 30 * 1000)
|
@cacheFunc(60 * 30 * 1000)
|
||||||
static async getCookies(domain: string) {
|
static async getCookies(domain: string) {
|
||||||
if (domain.endsWith("qzone.qq.com")) {
|
if (domain.endsWith("qzone.qq.com")) {
|
||||||
let data = (await NTQQUserApi.getQzoneCookies());
|
let data = (await NTQQUserApi.getQzoneCookies())
|
||||||
const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + selfInfo.uin + '; uin=o' + selfInfo.uin;
|
const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + selfInfo.uin + '; uin=o' + selfInfo.uin
|
||||||
return { bkn: NTQQUserApi.genBkn(data.p_skey), cookies: CookieValue };
|
return { bkn: NTQQUserApi.genBkn(data.p_skey), cookies: CookieValue }
|
||||||
}
|
}
|
||||||
const skey = await this.getSkey();
|
const skey = await this.getSkey()
|
||||||
const pskey = (await this.getPSkey([domain])).get(domain);
|
const pskey = (await this.getPSkey([domain])).get(domain)
|
||||||
if (!pskey || !skey) {
|
if (!pskey || !skey) {
|
||||||
throw new Error('获取Cookies失败')
|
throw new Error('获取Cookies失败')
|
||||||
}
|
}
|
||||||
const bkn = NTQQUserApi.genBkn(skey)
|
const bkn = NTQQUserApi.genBkn(skey)
|
||||||
const cookies = `p_skey=${pskey}; skey=${skey}; p_uin=o${selfInfo.uin}; uin=o${selfInfo.uin}`;
|
const cookies = `p_skey=${pskey}; skey=${skey}; p_uin=o${selfInfo.uin}; uin=o${selfInfo.uin}`
|
||||||
return { cookies, bkn }
|
return { cookies, bkn }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +195,8 @@ export class NTQQUserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
|
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
|
||||||
const res = await wrapperApi.NodeIQQNTWrapperSession.getTipOffService().getPskey(domains, true)
|
const session = getSession()
|
||||||
|
const res = await session?.getTipOffService().getPskey(domains, true)
|
||||||
if (res.result !== 0) {
|
if (res.result !== 0) {
|
||||||
throw new Error(`获取Pskey失败: ${res.errMsg}`)
|
throw new Error(`获取Pskey失败: ${res.errMsg}`)
|
||||||
}
|
}
|
||||||
@@ -159,7 +204,91 @@ export class NTQQUserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getClientKey(): Promise<ClientKeyData> {
|
static async getClientKey(): Promise<ClientKeyData> {
|
||||||
return await wrapperApi.NodeIQQNTWrapperSession.getTicketService().forceFetchClientKey('')
|
const session = getSession()
|
||||||
|
return await session?.getTicketService().forceFetchClientKey('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async like(uid: string, count = 1): Promise<{ result: number, errMsg: string, succCounts: number }> {
|
||||||
|
const session = getSession()
|
||||||
|
return session?.getProfileLikeService().setBuddyProfileLike({
|
||||||
|
friendUid: uid,
|
||||||
|
sourceId: 71,
|
||||||
|
doLikeCount: count,
|
||||||
|
doLikeTollCount: 0
|
||||||
|
})!
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getUidByUinV1(Uin: string) {
|
||||||
|
const session = getSession()
|
||||||
|
// 通用转换开始尝试
|
||||||
|
let uid = (await session?.getUixConvertService().getUid([Uin])!).uidInfo.get(Uin);
|
||||||
|
// Uid 好友转
|
||||||
|
if (!uid) {
|
||||||
|
friends.forEach((t) => {
|
||||||
|
if (t.uin == Uin) {
|
||||||
|
uid = t.uid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//Uid 群友列表转
|
||||||
|
if (!uid) {
|
||||||
|
for (let groupMembersList of groupMembers.values()) {
|
||||||
|
for (let GroupMember of groupMembersList.values()) {
|
||||||
|
if (GroupMember.uin == Uin) {
|
||||||
|
uid = GroupMember.uid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!uid) {
|
||||||
|
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
||||||
|
if (unveifyUid.indexOf('*') == -1) {
|
||||||
|
uid = unveifyUid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getUidByUinV2(Uin: string) {
|
||||||
|
const session = getSession()
|
||||||
|
let uid = (await session?.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])!).get(Uin)
|
||||||
|
if (uid) return uid
|
||||||
|
uid = (await session?.getGroupService().getUidByUins([Uin])!).uids.get(Uin)
|
||||||
|
if (uid) return uid
|
||||||
|
uid = (await session?.getUixConvertService().getUid([Uin])!).uidInfo.get(Uin)
|
||||||
|
if (uid) return uid
|
||||||
|
console.log((await NTQQFriendApi.getBuddyIdMapCache(true)))
|
||||||
|
uid = (await NTQQFriendApi.getBuddyIdMapCache(true)).getValue(Uin)//从Buddy缓存获取Uid
|
||||||
|
if (uid) return uid
|
||||||
|
uid = (await NTQQFriendApi.getBuddyIdMap(true)).getValue(Uin)
|
||||||
|
if (uid) return uid
|
||||||
|
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUinV2(Uin)).detail.uid//从QQ Native 特殊转换
|
||||||
|
if (unveifyUid.indexOf("*") == -1) uid = unveifyUid
|
||||||
|
//if (uid) return uid
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getUidByUin(Uin: string) {
|
||||||
|
if (getBuildVersion() >= 26702) {
|
||||||
|
return await NTQQUserApi.getUidByUinV2(Uin)
|
||||||
|
}
|
||||||
|
return await NTQQUserApi.getUidByUinV1(Uin)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getUserDetailInfoByUinV2(Uin: string) {
|
||||||
|
return await NTEventDispatch.CallNoListenerEvent
|
||||||
|
<(Uin: string) => Promise<UserDetailInfoByUinV2>>(
|
||||||
|
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||||
|
5000,
|
||||||
|
Uin
|
||||||
|
)
|
||||||
|
}
|
||||||
|
static async getUserDetailInfoByUin(Uin: string) {
|
||||||
|
return NTEventDispatch.CallNoListenerEvent
|
||||||
|
<(Uin: string) => Promise<UserDetailInfoByUin>>(
|
||||||
|
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||||
|
5000,
|
||||||
|
Uin
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
import { WebGroupData, groups, selfInfo } from '@/common/data';
|
import { WebGroupData, groups, selfInfo } from '@/common/data'
|
||||||
import { log } from '@/common/utils/log';
|
import { log } from '@/common/utils/log'
|
||||||
import { NTQQUserApi } from './user';
|
import { NTQQUserApi } from './user'
|
||||||
import { RequestUtil } from '@/common/utils/request';
|
import { RequestUtil } from '@/common/utils/request'
|
||||||
|
|
||||||
export enum WebHonorType {
|
export enum WebHonorType {
|
||||||
ALL = 'all',
|
ALL = 'all',
|
||||||
TALKACTIVE = 'talkative',
|
TALKACTIVE = 'talkative',
|
||||||
@@ -10,6 +11,7 @@ export enum WebHonorType {
|
|||||||
STORONGE_NEWBI = 'strong_newbie',
|
STORONGE_NEWBI = 'strong_newbie',
|
||||||
EMOTION = 'emotion'
|
EMOTION = 'emotion'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupMember {
|
export interface WebApiGroupMember {
|
||||||
uin: number
|
uin: number
|
||||||
role: number
|
role: number
|
||||||
@@ -27,6 +29,7 @@ export interface WebApiGroupMember {
|
|||||||
qage: number
|
qage: number
|
||||||
rm: number
|
rm: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WebApiGroupMemberRet {
|
interface WebApiGroupMemberRet {
|
||||||
ec: number
|
ec: number
|
||||||
errcode: number
|
errcode: number
|
||||||
@@ -41,6 +44,7 @@ interface WebApiGroupMemberRet {
|
|||||||
search_count: number
|
search_count: number
|
||||||
extmode: number
|
extmode: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupNoticeFeed {
|
export interface WebApiGroupNoticeFeed {
|
||||||
u: number//发送者
|
u: number//发送者
|
||||||
fid: string//fid
|
fid: string//fid
|
||||||
@@ -69,6 +73,7 @@ export interface WebApiGroupNoticeFeed {
|
|||||||
is_read: number
|
is_read: number
|
||||||
is_all_confirm: number
|
is_all_confirm: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupNoticeRet {
|
export interface WebApiGroupNoticeRet {
|
||||||
ec: number
|
ec: number
|
||||||
em: string
|
em: string
|
||||||
@@ -89,6 +94,7 @@ export interface WebApiGroupNoticeRet {
|
|||||||
svrt: number
|
svrt: number
|
||||||
ad: number
|
ad: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GroupEssenceMsg {
|
interface GroupEssenceMsg {
|
||||||
group_code: string
|
group_code: string
|
||||||
msg_seq: number
|
msg_seq: number
|
||||||
@@ -102,6 +108,7 @@ interface GroupEssenceMsg {
|
|||||||
msg_content: any[]
|
msg_content: any[]
|
||||||
can_be_removed: true
|
can_be_removed: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupEssenceMsgRet {
|
export interface GroupEssenceMsgRet {
|
||||||
retcode: number
|
retcode: number
|
||||||
retmsg: string
|
retmsg: string
|
||||||
@@ -112,22 +119,24 @@ export interface GroupEssenceMsgRet {
|
|||||||
config_page_url: string
|
config_page_url: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebApi {
|
export class WebApi {
|
||||||
static async getGroupEssenceMsg(GroupCode: string, page_start: string): Promise<GroupEssenceMsgRet> {
|
static async getGroupEssenceMsg(GroupCode: string, page_start: string): Promise<GroupEssenceMsgRet | undefined> {
|
||||||
const {cookies: CookieValue, bkn: Bkn} = (await NTQQUserApi.getCookies('qun.qq.com'))
|
const { cookies: CookieValue, bkn: Bkn } = (await NTQQUserApi.getCookies('qun.qq.com'))
|
||||||
const url = 'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=' + Bkn + '&group_code=' + GroupCode + '&page_start=' + page_start + '&page_limit=20';
|
const url = 'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=' + Bkn + '&group_code=' + GroupCode + '&page_start=' + page_start + '&page_limit=20'
|
||||||
let ret;
|
let ret: GroupEssenceMsgRet
|
||||||
try {
|
try {
|
||||||
ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>(url, 'GET', '', { 'Cookie': CookieValue });
|
ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>(url, 'GET', '', { 'Cookie': CookieValue })
|
||||||
} catch {
|
} catch {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
//console.log(url, CookieValue);
|
//console.log(url, CookieValue)
|
||||||
if (ret.retcode !== 0) {
|
if (ret.retcode !== 0) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
return ret;
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
static async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
||||||
log('webapi 获取群成员', GroupCode);
|
log('webapi 获取群成员', GroupCode);
|
||||||
let MemberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
let MemberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
||||||
@@ -190,6 +199,7 @@ export class WebApi {
|
|||||||
// const res = await this.request(url);
|
// const res = await this.request(url);
|
||||||
// return await res.json();
|
// return await res.json();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static async setGroupNotice(GroupCode: string, Content: string = '') {
|
static async setGroupNotice(GroupCode: string, Content: string = '') {
|
||||||
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
|
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
|
||||||
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
|
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
|
||||||
@@ -213,6 +223,7 @@ export class WebApi {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
static async getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
||||||
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com']))['qun.qq.com'];
|
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com']))['qun.qq.com'];
|
||||||
const _Skey = await NTQQUserApi.getSkey();
|
const _Skey = await NTQQUserApi.getSkey();
|
||||||
@@ -236,6 +247,7 @@ export class WebApi {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static genBkn(sKey: string) {
|
static genBkn(sKey: string) {
|
||||||
sKey = sKey || '';
|
sKey = sKey || '';
|
||||||
let hash = 5381;
|
let hash = 5381;
|
||||||
@@ -247,6 +259,7 @@ export class WebApi {
|
|||||||
|
|
||||||
return (hash & 0x7FFFFFFF).toString();
|
return (hash & 0x7FFFFFFF).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
//实现未缓存 考虑2h缓存
|
//实现未缓存 考虑2h缓存
|
||||||
static async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
static async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
||||||
async function getDataInternal(Internal_groupCode: string, Internal_type: number) {
|
async function getDataInternal(Internal_groupCode: string, Internal_type: number) {
|
||||||
|
@@ -27,7 +27,7 @@ export class NTQQWindowApi {
|
|||||||
static async openWindow<R = GeneralCallResult>(
|
static async openWindow<R = GeneralCallResult>(
|
||||||
ntQQWindow: NTQQWindow,
|
ntQQWindow: NTQQWindow,
|
||||||
args: any[],
|
args: any[],
|
||||||
cbCmd: ReceiveCmd = null,
|
cbCmd: ReceiveCmd | null = null,
|
||||||
autoCloseSeconds: number = 2,
|
autoCloseSeconds: number = 2,
|
||||||
) {
|
) {
|
||||||
const result = await callNTQQApi<R>({
|
const result = await callNTQQApi<R>({
|
||||||
|
@@ -21,7 +21,7 @@ import { log } from '../common/utils/log'
|
|||||||
import { defaultVideoThumb, getVideoInfo } from '../common/utils/video'
|
import { defaultVideoThumb, getVideoInfo } from '../common/utils/video'
|
||||||
import { encodeSilk } from '../common/utils/audio'
|
import { encodeSilk } from '../common/utils/audio'
|
||||||
import { isNull } from '../common/utils'
|
import { isNull } from '../common/utils'
|
||||||
import faceConfig from './face_config.json';
|
import faceConfig from './face_config.json'
|
||||||
|
|
||||||
export const mFaceCache = new Map<string, string>() // emojiId -> faceName
|
export const mFaceCache = new Map<string, string>() // emojiId -> faceName
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ export class SendMsgElementConstructor {
|
|||||||
if (faceId >= 222){
|
if (faceId >= 222){
|
||||||
faceType = 2
|
faceType = 2
|
||||||
}
|
}
|
||||||
if (face.AniStickerType){
|
if (face?.AniStickerType){
|
||||||
faceType = 3;
|
faceType = 3;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -292,10 +292,10 @@ export class SendMsgElementConstructor {
|
|||||||
faceElement: {
|
faceElement: {
|
||||||
faceIndex: faceId,
|
faceIndex: faceId,
|
||||||
faceType,
|
faceType,
|
||||||
faceText: face.QDes,
|
faceText: face?.QDes,
|
||||||
stickerId: face.AniStickerId,
|
stickerId: face?.AniStickerId,
|
||||||
stickerType: face.AniStickerType,
|
stickerType: face?.AniStickerType,
|
||||||
packId: face.AniStickerPackId,
|
packId: face?.AniStickerPackId,
|
||||||
sourceType: 1,
|
sourceType: 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ export class SendMsgElementConstructor {
|
|||||||
stickerId: '33',
|
stickerId: '33',
|
||||||
sourceType: 1,
|
sourceType: 1,
|
||||||
stickerType: 2,
|
stickerType: 2,
|
||||||
resultId: resultId.toString(),
|
resultId: resultId?.toString(),
|
||||||
surpriseId: '',
|
surpriseId: '',
|
||||||
// "randomType": 1,
|
// "randomType": 1,
|
||||||
},
|
},
|
||||||
@@ -351,7 +351,7 @@ export class SendMsgElementConstructor {
|
|||||||
stickerId: '34',
|
stickerId: '34',
|
||||||
sourceType: 1,
|
sourceType: 1,
|
||||||
stickerType: 2,
|
stickerType: 2,
|
||||||
resultId: resultId.toString(),
|
resultId: resultId?.toString(),
|
||||||
surpriseId: '',
|
surpriseId: '',
|
||||||
// "randomType": 1,
|
// "randomType": 1,
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { BrowserWindow } from 'electron'
|
import type { BrowserWindow } from 'electron'
|
||||||
import { NTQQApiClass, NTQQApiMethod } from './ntcall'
|
import { NTQQApiClass, NTQQApiMethod } from './ntcall'
|
||||||
import { NTQQMsgApi, sendMessagePool } from './api/msg'
|
import { NTQQMsgApi, sendMessagePool } from './api/msg'
|
||||||
import { CategoryFriend, ChatType, Group, GroupMember, GroupMemberRole, RawMessage, User } from './types'
|
import { CategoryFriend, ChatType, Group, GroupMember, GroupMemberRole, RawMessage, User } from './types'
|
||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
uidMaps,
|
uidMaps,
|
||||||
} from '@/common/data'
|
} from '@/common/data'
|
||||||
import { OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
import { OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
||||||
import { getConfigUtil, HOOK_LOG } from '@/common/config'
|
import { getConfigUtil, HOOK_LOG } from '@/common/config'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
@@ -23,6 +22,8 @@ import { log } from '@/common/utils'
|
|||||||
import { isNumeric, sleep } from '@/common/utils'
|
import { isNumeric, sleep } from '@/common/utils'
|
||||||
import { OB11Constructor } from '../onebot11/constructor'
|
import { OB11Constructor } from '../onebot11/constructor'
|
||||||
import { OB11GroupCardEvent } from '../onebot11/event/notice/OB11GroupCardEvent'
|
import { OB11GroupCardEvent } from '../onebot11/event/notice/OB11GroupCardEvent'
|
||||||
|
import { OB11GroupAdminNoticeEvent } from '../onebot11/event/notice/OB11GroupAdminNoticeEvent'
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
|
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
|||||||
let isLogger = false
|
let isLogger = false
|
||||||
try {
|
try {
|
||||||
isLogger = args[0]?.eventName?.startsWith('ns-LoggerApi')
|
isLogger = args[0]?.eventName?.startsWith('ns-LoggerApi')
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
if (!isLogger) {
|
if (!isLogger) {
|
||||||
try {
|
try {
|
||||||
HOOK_LOG && log(`received ntqq api message: ${channel}`, args)
|
HOOK_LOG && log(`received ntqq api message: ${channel}`, args)
|
||||||
@@ -101,7 +102,7 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
|||||||
try {
|
try {
|
||||||
let _ = hook.hookFunc(receiveData.payload)
|
let _ = hook.hookFunc(receiveData.payload)
|
||||||
if (hook.hookFunc.constructor.name === 'AsyncFunction') {
|
if (hook.hookFunc.constructor.name === 'AsyncFunction') {
|
||||||
;(_ as Promise<void>).then()
|
; (_ as Promise<void>).then()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('hook error', e, receiveData.payload)
|
log('hook error', e, receiveData.payload)
|
||||||
@@ -122,7 +123,7 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
|||||||
delete hookApiCallbacks[callbackId]
|
delete hookApiCallbacks[callbackId]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('hookNTQQApiReceive error', e.stack.toString(), args)
|
log('hookNTQQApiReceive error', e.stack.toString(), args)
|
||||||
}
|
}
|
||||||
originalSend.call(window.webContents, channel, ...args)
|
originalSend.call(window.webContents, channel, ...args)
|
||||||
@@ -141,11 +142,11 @@ export function hookNTQQApiCall(window: BrowserWindow) {
|
|||||||
let isLogger = false
|
let isLogger = false
|
||||||
try {
|
try {
|
||||||
isLogger = args[3][0].eventName.startsWith('ns-LoggerApi')
|
isLogger = args[3][0].eventName.startsWith('ns-LoggerApi')
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
if (!isLogger) {
|
if (!isLogger) {
|
||||||
try {
|
try {
|
||||||
HOOK_LOG && log('call NTQQ api', thisArg, args)
|
HOOK_LOG && log('call NTQQ api', thisArg, args)
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
try {
|
try {
|
||||||
const _args: unknown[] = args[3][1]
|
const _args: unknown[] = args[3][1]
|
||||||
const cmdName: NTQQApiMethod = _args[0] as NTQQApiMethod
|
const cmdName: NTQQApiMethod = _args[0] as NTQQApiMethod
|
||||||
@@ -156,7 +157,7 @@ export function hookNTQQApiCall(window: BrowserWindow) {
|
|||||||
try {
|
try {
|
||||||
let _ = hook.hookFunc(callParams)
|
let _ = hook.hookFunc(callParams)
|
||||||
if (hook.hookFunc.constructor.name === 'AsyncFunction') {
|
if (hook.hookFunc.constructor.name === 'AsyncFunction') {
|
||||||
;(_ as Promise<void>).then()
|
(_ as Promise<void>).then()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('hook call error', e, _args)
|
log('hook call error', e, _args)
|
||||||
@@ -164,7 +165,7 @@ export function hookNTQQApiCall(window: BrowserWindow) {
|
|||||||
}).then()
|
}).then()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
return target.apply(thisArg, args)
|
return target.apply(thisArg, args)
|
||||||
},
|
},
|
||||||
@@ -188,7 +189,7 @@ export function hookNTQQApiCall(window: BrowserWindow) {
|
|||||||
let ret = target.apply(thisArg, args)
|
let ret = target.apply(thisArg, args)
|
||||||
try {
|
try {
|
||||||
HOOK_LOG && log('call NTQQ invoke api return', ret)
|
HOOK_LOG && log('call NTQQ invoke api return', ret)
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
return ret
|
return ret
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -203,7 +204,7 @@ export function registerReceiveHook<PayloadType>(
|
|||||||
method: ReceiveCmd | ReceiveCmd[],
|
method: ReceiveCmd | ReceiveCmd[],
|
||||||
hookFunc: (payload: PayloadType) => void,
|
hookFunc: (payload: PayloadType) => void,
|
||||||
): string {
|
): string {
|
||||||
const id = uuidv4()
|
const id = randomUUID()
|
||||||
if (!Array.isArray(method)) {
|
if (!Array.isArray(method)) {
|
||||||
method = [method]
|
method = [method]
|
||||||
}
|
}
|
||||||
@@ -267,7 +268,7 @@ async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
|
|||||||
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
||||||
|
|
||||||
if (members) {
|
if (members) {
|
||||||
existGroup.members = members
|
existGroup.members = Array.from(members.values())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,16 +287,16 @@ async function processGroupEvent(payload: { groupList: Group[] }) {
|
|||||||
await sleep(200) // 如果请求QQ API的速度过快,通常无法正确拉取到最新的群信息,因此这里人为引入一个延时
|
await sleep(200) // 如果请求QQ API的速度过快,通常无法正确拉取到最新的群信息,因此这里人为引入一个延时
|
||||||
const newMembers = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
const newMembers = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
||||||
|
|
||||||
group.members = newMembers
|
group.members = Array.from(newMembers.values())
|
||||||
const newMembersSet = new Set<string>() // 建立索引降低时间复杂度
|
const newMembersSet = new Set<string>() // 建立索引降低时间复杂度
|
||||||
|
|
||||||
for (const member of newMembers) {
|
for (const member of newMembers) {
|
||||||
newMembersSet.add(member.uin)
|
newMembersSet.add(member[1].uin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断bot是否是管理员,如果是管理员不需要从这里得知有人退群,这里的退群无法得知是主动退群还是被踢
|
// 判断bot是否是管理员,如果是管理员不需要从这里得知有人退群,这里的退群无法得知是主动退群还是被踢
|
||||||
let bot = await getGroupMember(group.groupCode, selfInfo.uin)
|
let bot = await getGroupMember(group.groupCode, selfInfo.uin)
|
||||||
if (bot.role == GroupMemberRole.admin || bot.role == GroupMemberRole.owner) {
|
if (bot?.role == GroupMemberRole.admin || bot?.role == GroupMemberRole.owner) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const member of oldMembers) {
|
for (const member of oldMembers) {
|
||||||
@@ -319,7 +320,7 @@ async function processGroupEvent(payload: { groupList: Group[] }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateGroups(newGroupList, false).then()
|
updateGroups(newGroupList, false).then()
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
updateGroups(payload.groupList).then()
|
updateGroups(payload.groupList).then()
|
||||||
log('更新群信息错误', e.stack.toString())
|
log('更新群信息错误', e.stack.toString())
|
||||||
}
|
}
|
||||||
@@ -327,7 +328,7 @@ async function processGroupEvent(payload: { groupList: Group[] }) {
|
|||||||
|
|
||||||
export async function startHook() {
|
export async function startHook() {
|
||||||
|
|
||||||
// 群列表变动
|
// 群列表变动
|
||||||
registerReceiveHook<{ groupList: Group[]; updateType: number }>(ReceiveCmdS.GROUPS, (payload) => {
|
registerReceiveHook<{ groupList: Group[]; updateType: number }>(ReceiveCmdS.GROUPS, (payload) => {
|
||||||
// updateType 3是群列表变动,2是群成员变动
|
// updateType 3是群列表变动,2是群成员变动
|
||||||
// log("群列表变动", payload.updateType, payload.groupList)
|
// log("群列表变动", payload.updateType, payload.groupList)
|
||||||
@@ -369,6 +370,14 @@ export async function startHook() {
|
|||||||
postOb11Event(
|
postOb11Event(
|
||||||
new OB11GroupCardEvent(parseInt(groupCode), parseInt(member.uin), member.cardName, existMember.cardName),
|
new OB11GroupCardEvent(parseInt(groupCode), parseInt(member.uin), member.cardName, existMember.cardName),
|
||||||
)
|
)
|
||||||
|
} else if (member.role != existMember.role) {
|
||||||
|
log('有管理员变动通知')
|
||||||
|
const groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent(
|
||||||
|
member.role == GroupMemberRole.admin ? 'set' : 'unset',
|
||||||
|
parseInt(groupCode),
|
||||||
|
parseInt(member.uin)
|
||||||
|
)
|
||||||
|
postOb11Event(groupAdminNoticeEvent, true)
|
||||||
}
|
}
|
||||||
Object.assign(existMember, member)
|
Object.assign(existMember, member)
|
||||||
}
|
}
|
||||||
@@ -389,7 +398,7 @@ export async function startHook() {
|
|||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
// 好友列表变动
|
// 好友列表变动
|
||||||
registerReceiveHook<{
|
registerReceiveHook<{
|
||||||
data: CategoryFriend[]
|
data: CategoryFriend[]
|
||||||
}>(ReceiveCmdS.FRIENDS, (payload) => {
|
}>(ReceiveCmdS.FRIENDS, (payload) => {
|
||||||
@@ -445,7 +454,7 @@ export async function startHook() {
|
|||||||
const pttPath = msgElement.pttElement?.filePath
|
const pttPath = msgElement.pttElement?.filePath
|
||||||
const filePath = msgElement.fileElement?.filePath
|
const filePath = msgElement.fileElement?.filePath
|
||||||
const videoPath = msgElement.videoElement?.filePath
|
const videoPath = msgElement.videoElement?.filePath
|
||||||
const videoThumbPath: string[] = [...msgElement.videoElement?.thumbPath.values()]
|
const videoThumbPath: string[] = [...msgElement.videoElement.thumbPath?.values()!]
|
||||||
const pathList = [picPath, ...picThumbPath, pttPath, filePath, videoPath, ...videoThumbPath]
|
const pathList = [picPath, ...picThumbPath, pttPath, filePath, videoPath, ...videoThumbPath]
|
||||||
if (msgElement.picElement) {
|
if (msgElement.picElement) {
|
||||||
pathList.push(...Object.values(msgElement.picElement.thumbPath))
|
pathList.push(...Object.values(msgElement.picElement.thumbPath))
|
||||||
@@ -463,7 +472,7 @@ export async function startHook() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, getConfigUtil().getConfig().autoDeleteFileSecond * 1000)
|
}, getConfigUtil().getConfig().autoDeleteFileSecond! * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -478,7 +487,7 @@ export async function startHook() {
|
|||||||
if (sendCallback) {
|
if (sendCallback) {
|
||||||
try {
|
try {
|
||||||
sendCallback(message)
|
sendCallback(message)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('receive self msg error', e.stack)
|
log('receive self msg error', e.stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,8 +519,8 @@ export async function startHook() {
|
|||||||
NTQQMsgApi.getMsgHistory(peer, '', 20).then(({ msgList }) => {
|
NTQQMsgApi.getMsgHistory(peer, '', 20).then(({ msgList }) => {
|
||||||
let lastTempMsg = msgList.pop()
|
let lastTempMsg = msgList.pop()
|
||||||
log('激活窗口之前的第一条临时会话消息:', lastTempMsg)
|
log('激活窗口之前的第一条临时会话消息:', lastTempMsg)
|
||||||
if (Date.now() / 1000 - parseInt(lastTempMsg.msgTime) < 5) {
|
if (Date.now() / 1000 - parseInt(lastTempMsg?.msgTime!) < 5) {
|
||||||
OB11Constructor.message(lastTempMsg).then((r) => postOb11Event(r))
|
OB11Constructor.message(lastTempMsg!).then((r) => postOb11Event(r))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -542,5 +551,4 @@ export async function startHook() {
|
|||||||
log('重新激活聊天窗口', peer, { result: r.result, errMsg: r.errMsg })
|
log('重新激活聊天窗口', peer, { result: r.result, errMsg: r.errMsg })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
240
src/ntqqapi/listeners/NodeIKernelGroupListener.ts
Normal file
240
src/ntqqapi/listeners/NodeIKernelGroupListener.ts
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
import { Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/ntqqapi/types'
|
||||||
|
|
||||||
|
interface IGroupListener {
|
||||||
|
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void
|
||||||
|
|
||||||
|
onGroupExtListUpdate(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void
|
||||||
|
|
||||||
|
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void
|
||||||
|
|
||||||
|
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupDetailInfoChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupAllInfoChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupsMsgMaskResult(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupConfMemberChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupBulletinChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGetGroupBulletinListResult(...args: unknown[]): void
|
||||||
|
|
||||||
|
onMemberListChange(arg: {
|
||||||
|
sceneId: string,
|
||||||
|
ids: string[],
|
||||||
|
infos: Map<string, GroupMember>,
|
||||||
|
finish: boolean,
|
||||||
|
hasRobot: boolean
|
||||||
|
}): void
|
||||||
|
|
||||||
|
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>): void
|
||||||
|
|
||||||
|
onSearchMemberChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupStatisticInfoChange(...args: unknown[]): void
|
||||||
|
|
||||||
|
onJoinGroupNotify(...args: unknown[]): void
|
||||||
|
|
||||||
|
onShutUpMemberListChanged(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupBulletinRemindNotify(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupFirstBulletinNotify(...args: unknown[]): void
|
||||||
|
|
||||||
|
onJoinGroupNoVerifyFlag(...args: unknown[]): void
|
||||||
|
|
||||||
|
onGroupArkInviteStateResult(...args: unknown[]): void
|
||||||
|
// 发现于Win 9.9.9 23159
|
||||||
|
onGroupMemberLevelInfoChange(...args: unknown[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelGroupListener extends IGroupListener {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
|
new(listener: IGroupListener): NodeIKernelGroupListener
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GroupListener implements IGroupListener {
|
||||||
|
// 发现于Win 9.9.9 23159
|
||||||
|
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupAllInfoChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupConfMemberChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupDetailInfoChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupExtListUpdate(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinGroupNotify(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onMemberListChange(arg: {
|
||||||
|
sceneId: string,
|
||||||
|
ids: string[],
|
||||||
|
infos: Map<string, GroupMember>, // uid -> GroupMember
|
||||||
|
finish: boolean,
|
||||||
|
hasRobot: boolean
|
||||||
|
}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchMemberChange(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onShutUpMemberListChanged(...args: unknown[]) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DebugGroupListener implements IGroupListener {
|
||||||
|
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||||
|
console.log('onGroupMemberLevelInfoChange:', ...args)
|
||||||
|
}
|
||||||
|
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||||
|
console.log('onGetGroupBulletinListResult:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupAllInfoChange(...args: unknown[]) {
|
||||||
|
console.log('onGroupAllInfoChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinChange(...args: unknown[]) {
|
||||||
|
console.log('onGroupBulletinChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||||
|
console.log('onGroupBulletinRemindNotify:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||||
|
console.log('onGroupArkInviteStateResult:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||||
|
console.log('onGroupBulletinRichMediaDownloadComplete:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupConfMemberChange(...args: unknown[]) {
|
||||||
|
console.log('onGroupConfMemberChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupDetailInfoChange(...args: unknown[]) {
|
||||||
|
console.log('onGroupDetailInfoChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupExtListUpdate(...args: unknown[]) {
|
||||||
|
console.log('onGroupExtListUpdate:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||||
|
console.log('onGroupFirstBulletinNotify:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupListUpdate(...args: unknown[]) {
|
||||||
|
console.log('onGroupListUpdate:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupNotifiesUpdated(...args: unknown[]) {
|
||||||
|
console.log('onGroupNotifiesUpdated:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||||
|
console.log('onGroupBulletinRichMediaProgressUpdate:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||||
|
console.log('onGroupNotifiesUnreadCountUpdated:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||||
|
console.log('onGroupSingleScreenNotifies:')
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||||
|
console.log('onGroupsMsgMaskResult:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||||
|
console.log('onGroupStatisticInfoChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinGroupNotify(...args: unknown[]) {
|
||||||
|
console.log('onJoinGroupNotify:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||||
|
console.log('onJoinGroupNoVerifyFlag:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||||
|
console.log('onMemberInfoChange:', groupCode, changeType, members)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMemberListChange(...args: unknown[]) {
|
||||||
|
console.log('onMemberListChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchMemberChange(...args: unknown[]) {
|
||||||
|
console.log('onSearchMemberChange:', ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
onShutUpMemberListChanged(...args: unknown[]) {
|
||||||
|
console.log('onShutUpMemberListChanged:', ...args)
|
||||||
|
}
|
||||||
|
}
|
514
src/ntqqapi/listeners/NodeIKernelMsgListener.ts
Normal file
514
src/ntqqapi/listeners/NodeIKernelMsgListener.ts
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
import { ChatType, RawMessage } from '@/ntqqapi/types'
|
||||||
|
|
||||||
|
export interface OnRichMediaDownloadCompleteParams {
|
||||||
|
fileModelId: string,
|
||||||
|
msgElementId: string,
|
||||||
|
msgId: string,
|
||||||
|
fileId: string,
|
||||||
|
fileProgress: string, // '0'
|
||||||
|
fileSpeed: string, // '0'
|
||||||
|
fileErrCode: string, // '0'
|
||||||
|
fileErrMsg: string,
|
||||||
|
fileDownType: number, // 暂时未知
|
||||||
|
thumbSize: number,
|
||||||
|
filePath: string,
|
||||||
|
totalSize: string,
|
||||||
|
trasferStatus: number,
|
||||||
|
step: number,
|
||||||
|
commonFileInfo: unknown | null,
|
||||||
|
fileSrvErrCode: string,
|
||||||
|
clientMsg: string,
|
||||||
|
businessId: number,
|
||||||
|
userTotalSpacePerDay: unknown | null,
|
||||||
|
userUsedSpacePerDay: unknown | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface onGroupFileInfoUpdateParamType {
|
||||||
|
retCode: number
|
||||||
|
retMsg: string
|
||||||
|
clientWording: string
|
||||||
|
isEnd: boolean
|
||||||
|
item: Array<any>
|
||||||
|
allFileCount: string
|
||||||
|
nextIndex: string
|
||||||
|
reqId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// sessionType: 1,
|
||||||
|
// chatType: 100,
|
||||||
|
// peerUid: 'u_PVQ3tl6K78xxxx',
|
||||||
|
// groupCode: '809079648',
|
||||||
|
// fromNick: '拾xxxx,
|
||||||
|
// sig: '0x'
|
||||||
|
// }
|
||||||
|
export interface TempOnRecvParams {
|
||||||
|
sessionType: number,//1
|
||||||
|
chatType: ChatType,//100
|
||||||
|
peerUid: string,//uid
|
||||||
|
groupCode: string,//gc
|
||||||
|
fromNick: string,//gc name
|
||||||
|
sig: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IKernelMsgListener {
|
||||||
|
onAddSendMsg(msgRecord: RawMessage): void
|
||||||
|
|
||||||
|
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void
|
||||||
|
|
||||||
|
onContactUnreadCntUpdate(hashMap: unknown): void
|
||||||
|
|
||||||
|
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void
|
||||||
|
|
||||||
|
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void
|
||||||
|
|
||||||
|
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onEmojiResourceUpdate(emojiResourceInfo: unknown): void
|
||||||
|
|
||||||
|
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onFileMsgCome(arrayList: unknown): void
|
||||||
|
|
||||||
|
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onFirstViewGroupGuildMapping(arrayList: unknown): void
|
||||||
|
|
||||||
|
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void
|
||||||
|
|
||||||
|
onGroupFileInfoAdd(groupItem: unknown): void
|
||||||
|
|
||||||
|
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void
|
||||||
|
|
||||||
|
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onGroupTransferInfoAdd(groupItem: unknown): void
|
||||||
|
|
||||||
|
onGroupTransferInfoUpdate(groupFileListResult: unknown): void
|
||||||
|
|
||||||
|
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void
|
||||||
|
|
||||||
|
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void
|
||||||
|
|
||||||
|
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void
|
||||||
|
|
||||||
|
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void
|
||||||
|
|
||||||
|
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void
|
||||||
|
|
||||||
|
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void
|
||||||
|
|
||||||
|
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onInputStatusPush(inputStatusInfo: unknown): void
|
||||||
|
|
||||||
|
onKickedOffLine(kickedInfo: unknown): void
|
||||||
|
|
||||||
|
onLineDev(arrayList: unknown): void
|
||||||
|
|
||||||
|
onLogLevelChanged(j2: unknown): void
|
||||||
|
|
||||||
|
onMsgAbstractUpdate(arrayList: unknown): void
|
||||||
|
|
||||||
|
onMsgBoxChanged(arrayList: unknown): void
|
||||||
|
|
||||||
|
onMsgDelete(contact: unknown, arrayList: unknown): void
|
||||||
|
|
||||||
|
onMsgEventListUpdate(hashMap: unknown): void
|
||||||
|
|
||||||
|
onMsgInfoListAdd(arrayList: unknown): void
|
||||||
|
|
||||||
|
onMsgInfoListUpdate(msgList: RawMessage[]): void
|
||||||
|
|
||||||
|
onMsgQRCodeStatusChanged(i2: unknown): void
|
||||||
|
|
||||||
|
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void
|
||||||
|
|
||||||
|
onMsgSecurityNotify(msgRecord: unknown): void
|
||||||
|
|
||||||
|
onMsgSettingUpdate(msgSetting: unknown): void
|
||||||
|
|
||||||
|
onNtFirstViewMsgSyncEnd(): void
|
||||||
|
|
||||||
|
onNtMsgSyncEnd(): void
|
||||||
|
|
||||||
|
onNtMsgSyncStart(): void
|
||||||
|
|
||||||
|
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onRecvGroupGuildFlag(i2: unknown): void
|
||||||
|
|
||||||
|
onRecvMsg(...arrayList: unknown[]): void
|
||||||
|
|
||||||
|
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void
|
||||||
|
|
||||||
|
onRecvOnlineFileMsg(arrayList: unknown): void
|
||||||
|
|
||||||
|
onRecvS2CMsg(arrayList: unknown): void
|
||||||
|
|
||||||
|
onRecvSysMsg(arrayList: unknown): void
|
||||||
|
|
||||||
|
onRecvUDCFlag(i2: unknown): void
|
||||||
|
|
||||||
|
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void
|
||||||
|
|
||||||
|
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void
|
||||||
|
|
||||||
|
onSearchGroupFileInfoUpdate(searchGroupFileResult:
|
||||||
|
{
|
||||||
|
result: {
|
||||||
|
retCode: number,
|
||||||
|
retMsg: string,
|
||||||
|
clientWording: string
|
||||||
|
},
|
||||||
|
syncCookie: string,
|
||||||
|
totalMatchCount: number,
|
||||||
|
ownerMatchCount: number,
|
||||||
|
isEnd: boolean,
|
||||||
|
reqId: number,
|
||||||
|
item: Array<{
|
||||||
|
groupCode: string,
|
||||||
|
groupName: string,
|
||||||
|
uploaderUin: string,
|
||||||
|
uploaderName: string,
|
||||||
|
matchUin: string,
|
||||||
|
matchWords: Array<unknown>,
|
||||||
|
fileNameHits: Array<{
|
||||||
|
start: number,
|
||||||
|
end: number
|
||||||
|
}>,
|
||||||
|
fileModelId: string,
|
||||||
|
fileId: string,
|
||||||
|
fileName: string,
|
||||||
|
fileSize: string,
|
||||||
|
busId: number,
|
||||||
|
uploadTime: number,
|
||||||
|
modifyTime: number,
|
||||||
|
deadTime: number,
|
||||||
|
downloadTimes: number,
|
||||||
|
localPath: string
|
||||||
|
}>
|
||||||
|
}): void
|
||||||
|
|
||||||
|
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void
|
||||||
|
|
||||||
|
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void
|
||||||
|
|
||||||
|
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void
|
||||||
|
|
||||||
|
onUnreadCntAfterFirstView(hashMap: unknown): void
|
||||||
|
|
||||||
|
onUnreadCntUpdate(hashMap: unknown): void
|
||||||
|
|
||||||
|
onUserChannelTabStatusChanged(z: unknown): void
|
||||||
|
|
||||||
|
onUserOnlineStatusChanged(z: unknown): void
|
||||||
|
|
||||||
|
onUserTabStatusChanged(arrayList: unknown): void
|
||||||
|
|
||||||
|
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void
|
||||||
|
|
||||||
|
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void
|
||||||
|
|
||||||
|
// 第一次发现于Linux
|
||||||
|
onUserSecQualityChanged(...args: unknown[]): void
|
||||||
|
|
||||||
|
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void
|
||||||
|
|
||||||
|
onRedTouchChanged(...args: unknown[]): void
|
||||||
|
|
||||||
|
// 第一次发现于Win 9.9.9 23159
|
||||||
|
onBroadcastHelperProgerssUpdate(...args: unknown[]): void
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelMsgListener extends IKernelMsgListener {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
|
new(listener: IKernelMsgListener): NodeIKernelMsgListener
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class MsgListener implements IKernelMsgListener {
|
||||||
|
onAddSendMsg(msgRecord: RawMessage) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onContactUnreadCntUpdate(hashMap: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onEmojiDownloadComplete(emojiNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onEmojiResourceUpdate(emojiResourceInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onFileMsgCome(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onFirstViewGroupGuildMapping(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupFileInfoAdd(groupItem: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupGuildUpdate(groupGuildNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onGroupTransferInfoAdd(groupItem: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupTransferInfoUpdate(groupFileListResult: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputStatusPush(inputStatusInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onKickedOffLine(kickedInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onLineDev(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onLogLevelChanged(j2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgAbstractUpdate(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgBoxChanged(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgDelete(contact: unknown, arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgEventListUpdate(hashMap: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgInfoListAdd(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgInfoListUpdate(msgList: RawMessage[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgQRCodeStatusChanged(i2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgRecall(i2: unknown, str: unknown, j2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgSecurityNotify(msgRecord: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgSettingUpdate(msgSetting: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onNtFirstViewMsgSyncEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onNtMsgSyncEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onNtMsgSyncStart() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvGroupGuildFlag(i2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvMsg(arrayList: RawMessage[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvOnlineFileMsg(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvS2CMsg(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvSysMsg(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecvUDCFlag(i2: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRichMediaUploadComplete(fileTransNotifyInfo: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnreadCntAfterFirstView(hashMap: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnreadCntUpdate(hashMap: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserChannelTabStatusChanged(z: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserOnlineStatusChanged(z: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserTabStatusChanged(arrayList: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一次发现于Linux
|
||||||
|
onUserSecQualityChanged(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgWithRichLinkInfoUpdate(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRedTouchChanged(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// 第一次发现于Win 9.9.9-23159
|
||||||
|
onBroadcastHelperProgerssUpdate(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
44
src/ntqqapi/listeners/NodeIKernelProfileListener.ts
Normal file
44
src/ntqqapi/listeners/NodeIKernelProfileListener.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { User, UserDetailInfoListenerArg } from '@/ntqqapi/types'
|
||||||
|
|
||||||
|
interface IProfileListener {
|
||||||
|
onProfileSimpleChanged(...args: unknown[]): void
|
||||||
|
|
||||||
|
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void
|
||||||
|
|
||||||
|
onProfileDetailInfoChanged(profile: User): void
|
||||||
|
|
||||||
|
onStatusUpdate(...args: unknown[]): void
|
||||||
|
|
||||||
|
onSelfStatusChanged(...args: unknown[]): void
|
||||||
|
|
||||||
|
onStrangerRemarkChanged(...args: unknown[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelProfileListener extends IProfileListener {
|
||||||
|
new(listener: IProfileListener): NodeIKernelProfileListener
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProfileListener implements IProfileListener {
|
||||||
|
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
onProfileSimpleChanged(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onProfileDetailInfoChanged(profile: User) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onStatusUpdate(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelfStatusChanged(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onStrangerRemarkChanged(...args: unknown[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
3
src/ntqqapi/listeners/index.ts
Normal file
3
src/ntqqapi/listeners/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './NodeIKernelProfileListener'
|
||||||
|
export * from './NodeIKernelGroupListener'
|
||||||
|
export * from './NodeIKernelMsgListener'
|
@@ -1,19 +0,0 @@
|
|||||||
let Process = require('process')
|
|
||||||
let os = require('os')
|
|
||||||
Process.dlopenOrig = Process.dlopen
|
|
||||||
|
|
||||||
export const wrapperApi: any = {}
|
|
||||||
|
|
||||||
Process.dlopen = function(module, filename, flags = os.constants.dlopen.RTLD_LAZY) {
|
|
||||||
let dlopenRet = this.dlopenOrig(module, filename, flags)
|
|
||||||
for (let export_name in module.exports) {
|
|
||||||
module.exports[export_name] = new Proxy(module.exports[export_name], {
|
|
||||||
construct: (target, args, _newTarget) => {
|
|
||||||
let ret = new target(...args)
|
|
||||||
if (export_name === 'NodeIQQNTWrapperSession') wrapperApi.NodeIQQNTWrapperSession = ret
|
|
||||||
return ret
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return dlopenRet
|
|
||||||
}
|
|
@@ -1,10 +1,8 @@
|
|||||||
import { ipcMain } from 'electron'
|
import { ipcMain } from 'electron'
|
||||||
import { hookApiCallbacks, ReceiveCmd, ReceiveCmdS, registerReceiveHook, removeReceiveHook } from './hook'
|
import { hookApiCallbacks, ReceiveCmd, ReceiveCmdS, registerReceiveHook, removeReceiveHook } from './hook'
|
||||||
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import { log } from '../common/utils/log'
|
import { log } from '../common/utils/log'
|
||||||
import { NTQQWindow, NTQQWindowApi, NTQQWindows } from './api/window'
|
|
||||||
import { HOOK_LOG } from '../common/config'
|
import { HOOK_LOG } from '../common/config'
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
export enum NTQQApiClass {
|
export enum NTQQApiClass {
|
||||||
NT_API = 'ns-ntApi',
|
NT_API = 'ns-ntApi',
|
||||||
@@ -130,7 +128,7 @@ export function callNTQQApi<ReturnType>(params: NTQQApiParams) {
|
|||||||
args = args ?? []
|
args = args ?? []
|
||||||
timeout = timeout ?? 5
|
timeout = timeout ?? 5
|
||||||
afterFirstCmd = afterFirstCmd ?? true
|
afterFirstCmd = afterFirstCmd ?? true
|
||||||
const uuid = uuidv4()
|
const uuid = randomUUID()
|
||||||
HOOK_LOG && log('callNTQQApi', channel, className, methodName, args, uuid)
|
HOOK_LOG && log('callNTQQApi', channel, className, methodName, args, uuid)
|
||||||
return new Promise((resolve: (data: ReturnType) => void, reject) => {
|
return new Promise((resolve: (data: ReturnType) => void, reject) => {
|
||||||
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
|
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
|
||||||
|
125
src/ntqqapi/services/NodeIKernelBuddyService.ts
Normal file
125
src/ntqqapi/services/NodeIKernelBuddyService.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export enum BuddyListReqType {
|
||||||
|
KNOMAL,
|
||||||
|
KLETTER
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelBuddyService {
|
||||||
|
// 26702 以上
|
||||||
|
getBuddyListV2(callFrom: string, reqType: BuddyListReqType): Promise<GeneralCallResult & {
|
||||||
|
data: Array<{
|
||||||
|
categoryId: number,
|
||||||
|
categorySortId: number,
|
||||||
|
categroyName: string,
|
||||||
|
categroyMbCount: number,
|
||||||
|
onlineCount: number,
|
||||||
|
buddyUids: Array<string>
|
||||||
|
}>
|
||||||
|
}>
|
||||||
|
|
||||||
|
//26702 以上
|
||||||
|
getBuddyListFromCache(callFrom: string): Promise<Array<
|
||||||
|
{
|
||||||
|
categoryId: number,//9999应该跳过 那是兜底数据吧
|
||||||
|
categorySortId: number,//排序方式
|
||||||
|
categroyName: string,//分类名
|
||||||
|
categroyMbCount: number,//不懂
|
||||||
|
onlineCount: number,//在线数目
|
||||||
|
buddyUids: Array<string>//Uids
|
||||||
|
}>>
|
||||||
|
|
||||||
|
addKernelBuddyListener(listener: any): number
|
||||||
|
|
||||||
|
getAllBuddyCount(): number
|
||||||
|
|
||||||
|
removeKernelBuddyListener(listener: unknown): void
|
||||||
|
|
||||||
|
getBuddyList(nocache: boolean): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getBuddyNick(uid: number): string
|
||||||
|
|
||||||
|
getBuddyRemark(uid: number): string
|
||||||
|
|
||||||
|
setBuddyRemark(uid: number, remark: string): void
|
||||||
|
|
||||||
|
getAvatarUrl(uid: number): string
|
||||||
|
|
||||||
|
isBuddy(uid: string): boolean
|
||||||
|
|
||||||
|
getCategoryNameWithUid(uid: number): string
|
||||||
|
|
||||||
|
getTargetBuddySetting(uid: number): unknown
|
||||||
|
|
||||||
|
getTargetBuddySettingByType(uid: number, type: number): unknown
|
||||||
|
|
||||||
|
getBuddyReqUnreadCnt(): number
|
||||||
|
|
||||||
|
getBuddyReq(): unknown
|
||||||
|
|
||||||
|
delBuddyReq(uid: number): void
|
||||||
|
|
||||||
|
clearBuddyReqUnreadCnt(): void
|
||||||
|
|
||||||
|
reqToAddFriends(uid: number, msg: string): void
|
||||||
|
|
||||||
|
setSpacePermission(uid: number, permission: number): void
|
||||||
|
|
||||||
|
approvalFriendRequest(arg: {
|
||||||
|
friendUid: string
|
||||||
|
reqTime: string
|
||||||
|
accept: boolean
|
||||||
|
}): Promise<void>
|
||||||
|
|
||||||
|
delBuddy(uid: number): void
|
||||||
|
|
||||||
|
delBatchBuddy(uids: number[]): void
|
||||||
|
|
||||||
|
getSmartInfos(uid: number): unknown
|
||||||
|
|
||||||
|
setBuddyCategory(uid: number, category: number): void
|
||||||
|
|
||||||
|
setBatchBuddyCategory(uids: number[], category: number): void
|
||||||
|
|
||||||
|
addCategory(category: string): void
|
||||||
|
|
||||||
|
delCategory(category: string): void
|
||||||
|
|
||||||
|
renameCategory(oldCategory: string, newCategory: string): void
|
||||||
|
|
||||||
|
resortCategory(categorys: string[]): void
|
||||||
|
|
||||||
|
pullCategory(uid: number, category: string): void
|
||||||
|
|
||||||
|
setTop(uid: number, isTop: boolean): void
|
||||||
|
|
||||||
|
SetSpecialCare(uid: number, isSpecialCare: boolean): void
|
||||||
|
|
||||||
|
setMsgNotify(uid: number, isNotify: boolean): void
|
||||||
|
|
||||||
|
hasBuddyList(): boolean
|
||||||
|
|
||||||
|
setBlock(uid: number, isBlock: boolean): void
|
||||||
|
|
||||||
|
isBlocked(uid: number): boolean
|
||||||
|
|
||||||
|
modifyAddMeSetting(setting: unknown): void
|
||||||
|
|
||||||
|
getAddMeSetting(): unknown
|
||||||
|
|
||||||
|
getDoubtBuddyReq(): unknown
|
||||||
|
|
||||||
|
getDoubtBuddyUnreadNum(): number
|
||||||
|
|
||||||
|
approvalDoubtBuddyReq(uid: number, isAgree: boolean): void
|
||||||
|
|
||||||
|
delDoubtBuddyReq(uid: number): void
|
||||||
|
|
||||||
|
delAllDoubtBuddyReq(): void
|
||||||
|
|
||||||
|
reportDoubtBuddyReqUnread(): void
|
||||||
|
|
||||||
|
getBuddyRecommendContactArkJson(uid: string, phoneNumber: string): Promise<unknown>
|
||||||
|
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
249
src/ntqqapi/services/NodeIKernelGroupService.ts
Normal file
249
src/ntqqapi/services/NodeIKernelGroupService.ts
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
import { NodeIKernelGroupListener } from '@/ntqqapi/listeners'
|
||||||
|
import {
|
||||||
|
GroupExtParam,
|
||||||
|
GroupMember,
|
||||||
|
GroupMemberRole,
|
||||||
|
GroupNotifyTypes,
|
||||||
|
GroupRequestOperateTypes,
|
||||||
|
} from '@/ntqqapi/types'
|
||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
//高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底
|
||||||
|
|
||||||
|
export interface NodeIKernelGroupService {
|
||||||
|
getMemberCommonInfo(Req: {
|
||||||
|
groupCode: string,
|
||||||
|
startUin: string,
|
||||||
|
identifyFlag: string,
|
||||||
|
uinList: string[],
|
||||||
|
memberCommonFilter: {
|
||||||
|
memberUin: number,
|
||||||
|
uinFlag: number,
|
||||||
|
uinFlagExt: number,
|
||||||
|
uinMobileFlag: number,
|
||||||
|
shutUpTime: number,
|
||||||
|
privilege: number,
|
||||||
|
},
|
||||||
|
memberNum: number,
|
||||||
|
filterMethod: string,
|
||||||
|
onlineFlag: string,
|
||||||
|
realSpecialTitleFlag: number
|
||||||
|
}): Promise<unknown>
|
||||||
|
//26702
|
||||||
|
getGroupMemberLevelInfo(groupCode: string): Promise<unknown>
|
||||||
|
//26702
|
||||||
|
getGroupHonorList(groupCodes: Array<string>): unknown
|
||||||
|
|
||||||
|
getUinByUids(uins: string[]): Promise<{
|
||||||
|
errCode: number,
|
||||||
|
errMsg: string,
|
||||||
|
uins: Map<string, string>
|
||||||
|
}>
|
||||||
|
|
||||||
|
getUidByUins(uins: string[]): Promise<{
|
||||||
|
errCode: number,
|
||||||
|
errMsg: string,
|
||||||
|
uids: Map<string, string>
|
||||||
|
}>
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
checkGroupMemberCache(arrayList: Array<string>): Promise<unknown>
|
||||||
|
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
getGroupLatestEssenceList(groupCode: string): Promise<unknown>
|
||||||
|
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
shareDigest(Req: {
|
||||||
|
appId: string,
|
||||||
|
appType: number,
|
||||||
|
msgStyle: number,
|
||||||
|
recvUin: string,
|
||||||
|
sendType: number,
|
||||||
|
clientInfo: {
|
||||||
|
platform: number
|
||||||
|
},
|
||||||
|
richMsg: {
|
||||||
|
usingArk: boolean,
|
||||||
|
title: string,
|
||||||
|
summary: string,
|
||||||
|
url: string,
|
||||||
|
pictureUrl: string,
|
||||||
|
brief: string
|
||||||
|
}
|
||||||
|
}): Promise<unknown>
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
isEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
queryCachedEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||||
|
//26702(其实更早 但是我不知道)
|
||||||
|
fetchGroupEssenceList(Req: { groupCode: string, pageStart: number, pageLimit: number }, Arg: unknown): Promise<unknown>
|
||||||
|
//26702
|
||||||
|
getAllMemberList(groupCode: string, forceFetch: boolean): Promise<{
|
||||||
|
errCode: number,
|
||||||
|
errMsg: string,
|
||||||
|
result: {
|
||||||
|
ids: Array<{
|
||||||
|
uid: string,
|
||||||
|
index: number//0
|
||||||
|
}>,
|
||||||
|
infos: {},
|
||||||
|
finish: true,
|
||||||
|
hasRobot: false
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
|
||||||
|
setHeader(uid: string, path: string): unknown
|
||||||
|
|
||||||
|
addKernelGroupListener(listener: NodeIKernelGroupListener): number
|
||||||
|
|
||||||
|
removeKernelGroupListener(listenerId: unknown): void
|
||||||
|
|
||||||
|
createMemberListScene(groupCode: string, scene: string): string
|
||||||
|
|
||||||
|
destroyMemberListScene(SceneId: string): void
|
||||||
|
//About Arg (a) name: lastId 根据手Q来看为object {index:?(number),uid:string}
|
||||||
|
getNextMemberList(sceneId: string, a: undefined, num: number): Promise<{
|
||||||
|
errCode: number, errMsg: string,
|
||||||
|
result: { ids: string[], infos: Map<string, GroupMember>, finish: boolean, hasRobot: boolean }
|
||||||
|
}>
|
||||||
|
|
||||||
|
getPrevMemberList(): unknown
|
||||||
|
|
||||||
|
monitorMemberList(): unknown
|
||||||
|
|
||||||
|
searchMember(sceneId: string, keywords: string[]): unknown
|
||||||
|
|
||||||
|
getMemberInfo(group_id: string, uids: string[], forceFetch: boolean): Promise<GeneralCallResult>
|
||||||
|
//getMemberInfo [ '56729xxxx', [ 'u_4Nj08cwW5Hxxxxx' ], true ]
|
||||||
|
|
||||||
|
kickMember(groupCode: string, memberUids: string[], refuseForever: boolean, kickReason: string): Promise<void>
|
||||||
|
|
||||||
|
modifyMemberRole(groupCode: string, uid: string, role: GroupMemberRole): void
|
||||||
|
|
||||||
|
modifyMemberCardName(groupCode: string, uid: string, cardName: string): void
|
||||||
|
|
||||||
|
getTransferableMemberInfo(groupCode: string): unknown//获取整个群的
|
||||||
|
|
||||||
|
transferGroup(uid: string): void
|
||||||
|
|
||||||
|
getGroupList(force: boolean): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getGroupExtList(force: boolean): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getGroupDetailInfo(groupCode: string): unknown
|
||||||
|
|
||||||
|
getMemberExtInfo(param: GroupExtParam): Promise<unknown>//req
|
||||||
|
|
||||||
|
getGroupAllInfo(): unknown
|
||||||
|
|
||||||
|
getDiscussExistInfo(): unknown
|
||||||
|
|
||||||
|
getGroupConfMember(): unknown
|
||||||
|
|
||||||
|
getGroupMsgMask(): unknown
|
||||||
|
|
||||||
|
getGroupPortrait(): void
|
||||||
|
|
||||||
|
modifyGroupName(groupCode: string, groupName: string, arg: false): void
|
||||||
|
|
||||||
|
modifyGroupRemark(groupCode: string, remark: string): void
|
||||||
|
|
||||||
|
modifyGroupDetailInfo(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
setGroupMsgMask(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
changeGroupShieldSettingTemp(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
inviteToGroup(arg: unknown): void
|
||||||
|
|
||||||
|
inviteMembersToGroup(args: unknown[]): void
|
||||||
|
|
||||||
|
inviteMembersToGroupWithMsg(args: unknown): void
|
||||||
|
|
||||||
|
createGroup(arg: unknown): void
|
||||||
|
|
||||||
|
createGroupWithMembers(arg: unknown): void
|
||||||
|
|
||||||
|
quitGroup(groupCode: string): void
|
||||||
|
|
||||||
|
destroyGroup(groupCode: string): void
|
||||||
|
//获取单屏群通知列表
|
||||||
|
getSingleScreenNotifies(force: boolean, start_seq: string, num: number): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
clearGroupNotifies(groupCode: string): void
|
||||||
|
|
||||||
|
getGroupNotifiesUnreadCount(unknown: Boolean): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
clearGroupNotifiesUnreadCount(groupCode: string): void
|
||||||
|
|
||||||
|
operateSysNotify(
|
||||||
|
doubt: boolean,
|
||||||
|
operateMsg: {
|
||||||
|
operateType: GroupRequestOperateTypes, // 2 拒绝
|
||||||
|
targetMsg: {
|
||||||
|
seq: string, // 通知序列号
|
||||||
|
type: GroupNotifyTypes,
|
||||||
|
groupCode: string,
|
||||||
|
postscript: string
|
||||||
|
}
|
||||||
|
}): Promise<void>
|
||||||
|
|
||||||
|
setTop(groupCode: string, isTop: boolean): void
|
||||||
|
|
||||||
|
getGroupBulletin(groupCode: string): unknown
|
||||||
|
|
||||||
|
deleteGroupBulletin(groupCode: string, seq: string): void
|
||||||
|
|
||||||
|
publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
publishInstructionForNewcomers(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
uploadGroupBulletinPic(groupCode: string, pskey: string, imagePath: string): Promise<GeneralCallResult & {
|
||||||
|
errCode: number
|
||||||
|
picInfo?: {
|
||||||
|
id: string,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
|
||||||
|
downloadGroupBulletinRichMedia(groupCode: string): unknown
|
||||||
|
|
||||||
|
getGroupBulletinList(groupCode: string): unknown
|
||||||
|
|
||||||
|
getGroupStatisticInfo(groupCode: string): unknown
|
||||||
|
|
||||||
|
getGroupRemainAtTimes(groupCode: string): number
|
||||||
|
|
||||||
|
getJoinGroupNoVerifyFlag(groupCode: string): unknown
|
||||||
|
|
||||||
|
getGroupArkInviteState(groupCode: string): unknown
|
||||||
|
|
||||||
|
reqToJoinGroup(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
setGroupShutUp(groupCode: string, shutUp: boolean): void
|
||||||
|
|
||||||
|
getGroupShutUpMemberList(groupCode: string): unknown[]
|
||||||
|
|
||||||
|
setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>
|
||||||
|
|
||||||
|
getGroupRecommendContactArkJson(groupCode: string): unknown
|
||||||
|
|
||||||
|
getJoinGroupLink(groupCode: string): unknown
|
||||||
|
|
||||||
|
modifyGroupExtInfo(groupCode: string, arg: unknown): void
|
||||||
|
|
||||||
|
//需要提前判断是否存在 高版本新增
|
||||||
|
addGroupEssence(param: {
|
||||||
|
groupCode: string
|
||||||
|
msgRandom: number,
|
||||||
|
msgSeq: number
|
||||||
|
}): Promise<unknown>
|
||||||
|
//需要提前判断是否存在 高版本新增
|
||||||
|
removeGroupEssence(param: {
|
||||||
|
groupCode: string
|
||||||
|
msgRandom: number,
|
||||||
|
msgSeq: number
|
||||||
|
}): Promise<unknown>
|
||||||
|
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
3
src/ntqqapi/services/NodeIKernelMSFService.ts
Normal file
3
src/ntqqapi/services/NodeIKernelMSFService.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export interface NodeIKernelMSFService {
|
||||||
|
getServerTime(): string
|
||||||
|
}
|
744
src/ntqqapi/services/NodeIKernelMsgService.ts
Normal file
744
src/ntqqapi/services/NodeIKernelMsgService.ts
Normal file
@@ -0,0 +1,744 @@
|
|||||||
|
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/ntqqapi/types'
|
||||||
|
import { NodeIKernelMsgListener } from '@/ntqqapi/listeners/NodeIKernelMsgListener'
|
||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export interface QueryMsgsParams {
|
||||||
|
chatInfo: Peer,
|
||||||
|
filterMsgType: [],
|
||||||
|
filterSendersUid: string[],
|
||||||
|
filterMsgFromTime: string,
|
||||||
|
filterMsgToTime: string,
|
||||||
|
pageLimit: number,
|
||||||
|
isReverseOrder: boolean,
|
||||||
|
isIncludeCurrent: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TmpChatInfoApi {
|
||||||
|
errMsg: string
|
||||||
|
result: number
|
||||||
|
tmpChatInfo?: TmpChatInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TmpChatInfo {
|
||||||
|
chatType: number
|
||||||
|
fromNick: string
|
||||||
|
groupCode: string
|
||||||
|
peerUid: string
|
||||||
|
sessionType: number
|
||||||
|
sig: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelMsgService {
|
||||||
|
|
||||||
|
generateMsgUniqueId(chatType: number, time: string): string
|
||||||
|
|
||||||
|
addKernelMsgListener(nodeIKernelMsgListener: NodeIKernelMsgListener): number
|
||||||
|
|
||||||
|
sendMsg(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
recallMsg(peer: Peer, msgIds: string[]): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
addKernelMsgImportToolListener(arg: Object): unknown
|
||||||
|
|
||||||
|
removeKernelMsgListener(args: unknown): unknown
|
||||||
|
|
||||||
|
addKernelTempChatSigListener(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
removeKernelTempChatSigListener(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setAutoReplyTextList(AutoReplyText: Array<unknown>, i2: number): unknown
|
||||||
|
|
||||||
|
getAutoReplyTextList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getOnLineDev(): void
|
||||||
|
|
||||||
|
kickOffLine(DevInfo: Object): unknown
|
||||||
|
|
||||||
|
setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
fetchStatusMgrInfo(): unknown
|
||||||
|
|
||||||
|
fetchStatusUnitedConfigInfo(): unknown
|
||||||
|
|
||||||
|
getOnlineStatusSmallIconBasePath(): unknown
|
||||||
|
|
||||||
|
getOnlineStatusSmallIconFileNameByUrl(Url: string): unknown
|
||||||
|
|
||||||
|
downloadOnlineStatusSmallIconByUrl(arg0: number, arg1: string): unknown
|
||||||
|
|
||||||
|
getOnlineStatusBigIconBasePath(): unknown
|
||||||
|
|
||||||
|
downloadOnlineStatusBigIconByUrl(arg0: number, arg1: string): unknown
|
||||||
|
|
||||||
|
getOnlineStatusCommonPath(arg: string): unknown
|
||||||
|
|
||||||
|
getOnlineStatusCommonFileNameByUrl(Url: string): unknown
|
||||||
|
|
||||||
|
downloadOnlineStatusCommonByUrl(arg0: string, arg1: string): unknown
|
||||||
|
|
||||||
|
// this.tokenType = i2
|
||||||
|
// this.apnsToken = bArr
|
||||||
|
// this.voipToken = bArr2
|
||||||
|
// this.profileId = str
|
||||||
|
|
||||||
|
setToken(arg: Object): unknown
|
||||||
|
|
||||||
|
switchForeGround(): unknown
|
||||||
|
|
||||||
|
switchBackGround(arg: Object): unknown
|
||||||
|
|
||||||
|
//hex
|
||||||
|
setTokenForMqq(token: string): unknown
|
||||||
|
|
||||||
|
switchForeGroundForMqq(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
switchBackGroundForMqq(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgSetting(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMsgSetting(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addSendMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
cancelSendMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
switchToOfflineSendMsg(peer: Peer, MsgId: string): unknown
|
||||||
|
|
||||||
|
reqToOfflineSendMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
refuseReceiveOnlineFileMsg(peer: Peer, MsgId: string): unknown
|
||||||
|
|
||||||
|
resendMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
recallMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
reeditRecallMsg(...args: unknown[]): unknown
|
||||||
|
//调用请检查除开commentElements其余参数不能为null
|
||||||
|
forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
forwardMsgWithComment(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
forwardSubMsgWithComment(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
forwardRichMsgInVist(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
forwardFile(...args: unknown[]): unknown
|
||||||
|
//Array<Msg>, Peer from, Peer to
|
||||||
|
multiForwardMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
multiForwardMsgWithComment(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
deleteRecallMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
deleteRecallMsgForLocal(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalGrayTipMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalJsonGrayTipMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalJsonGrayTipMsgExt(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
IsLocalJsonTipValid(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalAVRecordMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalTofuRecordMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addLocalRecordMsg(Peer: Peer, msgId: string, ele: MessageElement, attr: Array<any> | number, front: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
deleteMsg(Peer: Peer, msgIds: Array<string>): Promise<any>
|
||||||
|
|
||||||
|
updateElementExtBufForUI(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
updateMsgRecordExtPbBufForUI(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
startMsgSync(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
startGuildMsgSync(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
isGuildChannelSync(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgUniqueId(UniqueId: string): string
|
||||||
|
|
||||||
|
isMsgMatched(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getOnlineFileMsgs(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getAllOnlineFileMsgs(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getLatestDbMsgs(peer: Peer, cnt: number): Promise<unknown>
|
||||||
|
|
||||||
|
getLastMessageList(peer: Peer[]): Promise<unknown>
|
||||||
|
|
||||||
|
getAioFirstViewLatestMsgs(peer: Peer, num: number): unknown
|
||||||
|
|
||||||
|
//deprecated 从9.9.15-26702版本开始,该接口已经废弃,请使用getMsgsEx
|
||||||
|
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & {
|
||||||
|
msgList: RawMessage[]
|
||||||
|
}>
|
||||||
|
|
||||||
|
// this.$peer = contact
|
||||||
|
// this.$msgTime = j2
|
||||||
|
// this.$clientSeq = j3
|
||||||
|
// this.$cnt = i2
|
||||||
|
|
||||||
|
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getMsgsWithStatus(params: {
|
||||||
|
peer: Peer
|
||||||
|
msgId: string
|
||||||
|
msgTime: unknown
|
||||||
|
cnt: unknown
|
||||||
|
queryOrder: boolean
|
||||||
|
isIncludeSelf: boolean
|
||||||
|
appid: unknown
|
||||||
|
}): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getMsgsByMsgId(peer: Peer, ids: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getRecallMsgsByMsgId(peer: Peer, MsgId: string[]): Promise<unknown>
|
||||||
|
|
||||||
|
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||||
|
|
||||||
|
getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown
|
||||||
|
|
||||||
|
getSourceOfReplyMsgV2(peer: Peer, RootMsgId: string, ReplyMsgId: string): unknown
|
||||||
|
|
||||||
|
getMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown
|
||||||
|
|
||||||
|
getSourceOfReplyMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown
|
||||||
|
//cnt clientSeq?并不是吧
|
||||||
|
getMsgsByTypeFilter(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilter: { type: number, subtype: Array<number> }): unknown
|
||||||
|
|
||||||
|
getMsgsByTypeFilters(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilters: Array<{ type: number, subtype: Array<number> }>): unknown
|
||||||
|
|
||||||
|
getMsgWithAbstractByFilterParam(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryMsgsWithFilter(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 该函数已被标记为废弃,请使用新的替代方法。
|
||||||
|
* 使用过滤条件查询消息列表的版本2接口。
|
||||||
|
*
|
||||||
|
* 该函数通过一系列过滤条件来查询特定聊天中的消息列表。这些条件包括消息类型、发送者、时间范围等。
|
||||||
|
* 函数返回一个Promise,解析为查询结果的未知类型对象。
|
||||||
|
*
|
||||||
|
* @param MsgId 消息ID,用于特定消息的查询。
|
||||||
|
* @param MsgTime 消息时间,用于指定消息的时间范围。
|
||||||
|
* @param param 查询参数对象,包含详细的过滤条件和分页信息。
|
||||||
|
* @param param.chatInfo 聊天信息,包括聊天类型和对方用户ID。
|
||||||
|
* @param param.filterMsgType 需要过滤的消息类型数组,留空表示不过滤。
|
||||||
|
* @param param.filterSendersUid 需要过滤的发送者用户ID数组。
|
||||||
|
* @param param.filterMsgFromTime 查询消息的起始时间。
|
||||||
|
* @param param.filterMsgToTime 查询消息的结束时间。
|
||||||
|
* @param param.pageLimit 每页的消息数量限制。
|
||||||
|
* @param param.isReverseOrder 是否按时间顺序倒序返回消息。
|
||||||
|
* @param param.isIncludeCurrent 是否包含当前页码。
|
||||||
|
* @returns 返回一个Promise,解析为查询结果的未知类型对象。
|
||||||
|
*/
|
||||||
|
queryMsgsWithFilterVer2(MsgId: string, MsgTime: string, param: QueryMsgsParams): Promise<unknown>
|
||||||
|
|
||||||
|
// this.chatType = i2
|
||||||
|
// this.peerUid = str
|
||||||
|
|
||||||
|
// this.chatInfo = new ChatInfo()
|
||||||
|
// this.filterMsgType = new ArrayList<>()
|
||||||
|
// this.filterSendersUid = new ArrayList<>()
|
||||||
|
// this.chatInfo = chatInfo
|
||||||
|
// this.filterMsgType = arrayList
|
||||||
|
// this.filterSendersUid = arrayList2
|
||||||
|
// this.filterMsgFromTime = j2
|
||||||
|
// this.filterMsgToTime = j3
|
||||||
|
// this.pageLimit = i2
|
||||||
|
// this.isReverseOrder = z
|
||||||
|
// this.isIncludeCurrent = z2
|
||||||
|
//queryMsgsWithFilterEx(0L, 0L, 0L, new QueryMsgsParams(new ChatInfo(2, str), new ArrayList(), new ArrayList(), 0L, 0L, 250, false, true))
|
||||||
|
queryMsgsWithFilterEx(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<GeneralCallResult & {
|
||||||
|
msgList: RawMessage[]
|
||||||
|
}>
|
||||||
|
//queryMsgsWithFilterEx(this.$msgId, this.$msgTime, this.$msgSeq, this.$param)
|
||||||
|
queryFileMsgsDesktop(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMsgRichInfoFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryPicOrVideoMsgs(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<unknown>
|
||||||
|
|
||||||
|
queryPicOrVideoMsgsDesktop(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>
|
||||||
|
|
||||||
|
queryTroopEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>
|
||||||
|
|
||||||
|
queryMsgsAndAbstractsWithFilter(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): unknown
|
||||||
|
|
||||||
|
setFocusOnGuild(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setFocusSession(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
enableFilterUnreadInfoNotify(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
enableFilterMsgAbstractNotify(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
onScenesChangeForSilenceMode(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getContactUnreadCnt(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildUnreadCntTabInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getAllGuildUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getAllJoinGuildCnt(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getAllDirectSessionUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getCategoryUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildFeedsUnreadCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setUnVisibleChannelCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setUnVisibleChannelTypeCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setVisibleGuildCntInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMsgRead(peer: Peer): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
setAllC2CAndGroupMsgRead(): Promise<unknown>
|
||||||
|
|
||||||
|
setGuildMsgRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setAllGuildMsgRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMsgReadAndReport(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setSpecificMsgReadAndReport(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setLocalMsgRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setGroupGuildMsgRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildGroupTransData(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setGroupGuildBubbleRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildGroupBubble(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchGroupGuildUnread(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setGroupGuildFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setGuildUDCFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setGuildTabUserFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setBuildMode(flag: number/*0 1 3*/): unknown
|
||||||
|
|
||||||
|
setConfigurationServiceData(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMarkUnreadFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getChannelEventFlow(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgEventFlow(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRichMediaFilePathForMobileQQSend(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRichMediaFilePathForGuild(arg: {
|
||||||
|
md5HexStr: string,
|
||||||
|
fileName: string,
|
||||||
|
elementType: ElementType,
|
||||||
|
elementSubType: number,
|
||||||
|
thumbSize: 0,
|
||||||
|
needCreate: true,
|
||||||
|
downloadType: 1,
|
||||||
|
file_uuid: ''
|
||||||
|
}): string
|
||||||
|
|
||||||
|
assembleMobileQQRichMediaFilePath(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFileThumbSavePathForSend(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFileThumbSavePath(...args: unknown[]): unknown
|
||||||
|
//猜测居多
|
||||||
|
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown
|
||||||
|
|
||||||
|
setPttPlayedState(...args: unknown[]): unknown
|
||||||
|
// NodeIQQNTWrapperSession fetchFavEmojiList [
|
||||||
|
// "",
|
||||||
|
// 48,
|
||||||
|
// true,
|
||||||
|
// true
|
||||||
|
// ]
|
||||||
|
fetchFavEmojiList(str: string, num: number, uk1: boolean, uk2: boolean): Promise<GeneralCallResult & {
|
||||||
|
emojiInfoList: Array<{
|
||||||
|
uin: string,
|
||||||
|
emoId: number,
|
||||||
|
emoPath: string,
|
||||||
|
isExist: boolean,
|
||||||
|
resId: string,
|
||||||
|
url: string,
|
||||||
|
md5: string,
|
||||||
|
emoOriginalPath: string,
|
||||||
|
thumbPath: string,
|
||||||
|
RomaingType: string,
|
||||||
|
isAPNG: false,
|
||||||
|
isMarkFace: false,
|
||||||
|
eId: string,
|
||||||
|
epId: string,
|
||||||
|
ocrWord: string,
|
||||||
|
modifyWord: string,
|
||||||
|
exposeNum: number,
|
||||||
|
clickNum: number,
|
||||||
|
desc: string
|
||||||
|
}>
|
||||||
|
}>
|
||||||
|
|
||||||
|
addFavEmoji(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmoticonList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmoticonShowImage(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmoticonAioImage(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmotionJsonFile(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMarketEmoticonPath(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMarketEmoticonPathBySync(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmoticonFaceImages(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchMarketEmoticonAuthDetail(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFavMarketEmoticonInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
addRecentUsedFace(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRecentUsedFaceList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMarketEmoticonEncryptKeys(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
downloadEmojiPic(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
deleteFavEmoji(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
modifyFavEmojiDesc(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryFavEmojiByDesc(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getHotPicInfoListSearchString(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getHotPicSearchResult(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getHotPicHotWords(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getHotPicJumpInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getEmojiResourcePath(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
JoinDragonGroupEmoji(JoinDragonGroupEmojiReq: any/*joinDragonGroupEmojiReq*/): unknown
|
||||||
|
|
||||||
|
getMsgAbstracts(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgAbstract(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgAbstractList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgAbstractListBySeqRange(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
refreshMsgAbstracts(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
refreshMsgAbstractsByGuildIds(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRichMediaElement(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
cancelGetRichMediaElement(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
refuseGetRichMediaElement(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
switchToOfflineGetRichMediaElement(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
downloadRichMedia(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFirstUnreadMsgSeq(args: {
|
||||||
|
peerUid: string
|
||||||
|
guildId: string
|
||||||
|
}): unknown
|
||||||
|
|
||||||
|
getFirstUnreadCommonMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFirstUnreadAtmeMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFirstUnreadAtallMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getNavigateInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getChannelFreqLimitInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRecentUseEmojiList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRecentEmojiList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setMsgEmojiLikes(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{
|
||||||
|
result: number,
|
||||||
|
errMsg: string,
|
||||||
|
emojiLikesList:
|
||||||
|
Array<{
|
||||||
|
tinyId: string,
|
||||||
|
nickName: string,
|
||||||
|
headUrl: string
|
||||||
|
}>,
|
||||||
|
cookie: string,
|
||||||
|
isLastPage: boolean,
|
||||||
|
isFirstPage: boolean
|
||||||
|
}>
|
||||||
|
|
||||||
|
setMsgEmojiLikesForRole(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
clickInlineKeyboardButton(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setCurOnScreenMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setCurOnScreenMsgForMsgEvent(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMiscData(key: string): unknown
|
||||||
|
|
||||||
|
setMiscData(key: string, value: string): unknown
|
||||||
|
|
||||||
|
getBookmarkData(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setBookmarkData(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
sendShowInputStatusReq(ChatType: number, EventType: number, toUid: string): Promise<unknown>
|
||||||
|
|
||||||
|
queryCalendar(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryFirstMsgSeq(peer: Peer, ...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryRoamCalendar(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryFirstRoamMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchLongMsg(peer: Peer, msgId: string): unknown
|
||||||
|
|
||||||
|
fetchLongMsgWithCb(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setIsStopKernelFetchLongMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
insertGameResultAsMsgToDb(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMultiMsg(...args: unknown[]): Promise<GeneralCallResult & {
|
||||||
|
msgList: RawMessage[]
|
||||||
|
}>
|
||||||
|
|
||||||
|
setDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
deleteDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getRecentHiddenSesionList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setRecentHiddenSession(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
delRecentHiddenSession(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getCurHiddenSession(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setCurHiddenSession(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setReplyDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getReplyDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
deleteReplyDraft(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getFirstUnreadAtMsg(peer: Peer): unknown
|
||||||
|
|
||||||
|
clearMsgRecords(...args: unknown[]): unknown//设置已读后调用我觉得比较好 清理记录 现在别了
|
||||||
|
|
||||||
|
IsExistOldDb(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
canImportOldDbMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setPowerStatus(z: boolean): unknown
|
||||||
|
|
||||||
|
canProcessDataMigration(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
importOldDbMsg(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
stopImportOldDbMsgAndroid(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
isMqqDataImportFinished(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getMqqDataImportTableNames(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getCurChatImportStatusByUin(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getDataImportUserLevel(): unknown
|
||||||
|
|
||||||
|
getMsgQRCode(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuestMsgAbstracts(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuestMsgByRange(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuestMsgAbstractByRange(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
registerSysMsgNotification(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
unregisterSysMsgNotification(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
enterOrExitAio(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
// this.peerUid = ""
|
||||||
|
// this.peerNickname = ""
|
||||||
|
// this.fromGroupCode = ""
|
||||||
|
// this.sig = new byte[0]
|
||||||
|
// this.selfUid = ""
|
||||||
|
// this.selfPhone = ""
|
||||||
|
// this.chatType = i2
|
||||||
|
// this.peerUid = str
|
||||||
|
// this.peerNickname = str2
|
||||||
|
// this.fromGroupCode = str3
|
||||||
|
// this.sig = bArr
|
||||||
|
// this.selfUid = str4
|
||||||
|
// this.selfPhone = str5
|
||||||
|
// this.gameSession = tempChatGameSession
|
||||||
|
prepareTempChat(args: unknown): unknown//主动临时消息 不做
|
||||||
|
|
||||||
|
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>
|
||||||
|
|
||||||
|
//chattype,uid->Promise<any>
|
||||||
|
getTempChatInfo(ChatType: number, Uid: string): Promise<TmpChatInfoApi>
|
||||||
|
|
||||||
|
setContactLocalTop(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
switchAnonymousChat(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
renameAnonyChatNick(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getAnonymousInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
updateAnonymousInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
sendSummonMsg(peer: Peer, MsgElement: unknown, MsgAttributeInfo: unknown): Promise<unknown>//频道的东西
|
||||||
|
|
||||||
|
outputGuildUnreadInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
checkMsgWithUrl(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
checkTabListStatus(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
insertMsgToMsgBox(peer: Peer, msgId: string, arg: 2006): unknown
|
||||||
|
|
||||||
|
isHitEmojiKeyword(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getKeyWordRelatedEmoji(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
recordEmoji(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
fetchGetHitEmotionsByWord(args: Object): Promise<unknown>//表情推荐?
|
||||||
|
|
||||||
|
deleteAllRoamMsgs(...args: unknown[]): unknown//漫游消息?
|
||||||
|
|
||||||
|
packRedBag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
grabRedBag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
pullDetail(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
selectPasswordRedBag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
pullRedBagPasswordList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
requestTianshuAdv(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
tianshuReport(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
tianshuMultiReport(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
GetMsgSubType(a0: number, a1: number): unknown
|
||||||
|
|
||||||
|
setIKernelPublicAccountAdapter(...args: unknown[]): unknown
|
||||||
|
//tempChatGameSession有关
|
||||||
|
createUidFromTinyId(fromTinyId: string, toTinyId: string): unknown
|
||||||
|
|
||||||
|
dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
dataMigrationGetMsgList(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
dataMigrationStopOperation(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
//新的希望
|
||||||
|
dataMigrationImportMsgPbRecord(DataMigrationMsgInfo: Array<{
|
||||||
|
extensionData: string//"Hex"
|
||||||
|
extraData: string //""
|
||||||
|
chatType: number
|
||||||
|
chatUin: string
|
||||||
|
msgType: number
|
||||||
|
msgTime: string
|
||||||
|
msgSeq: string
|
||||||
|
msgRandom: string
|
||||||
|
}>, DataMigrationResourceInfo: {
|
||||||
|
extraData: string
|
||||||
|
filePath: string
|
||||||
|
fileSize: string
|
||||||
|
msgRandom: string
|
||||||
|
msgSeq: string
|
||||||
|
msgSubType: number
|
||||||
|
msgType: number
|
||||||
|
}): unknown
|
||||||
|
|
||||||
|
dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
dataMigrationSetIOSPathPrefix(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getServiceAssistantSwitch(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setServiceAssistantSwitch(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setSubscribeFolderUsingSmallRedPoint(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
clearGuildNoticeRedPoint(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
clearFeedNoticeRedPoint(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
clearFeedSquareRead(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
IsC2CStyleChatType(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
IsTempChatType(uin: number): unknown//猜的
|
||||||
|
|
||||||
|
getGuildInteractiveNotification(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildNotificationAbstract(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
setFocusOnBase(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryArkInfo(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
queryUserSecQuality(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGuildMsgAbFlag(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getGroupMsgStorageTime(): unknown//这是嘛啊
|
||||||
|
|
||||||
|
}
|
22
src/ntqqapi/services/NodeIKernelProfileLikeService.ts
Normal file
22
src/ntqqapi/services/NodeIKernelProfileLikeService.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { BuddyProfileLikeReq } from '../types'
|
||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export interface NodeIKernelProfileLikeService {
|
||||||
|
addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void
|
||||||
|
|
||||||
|
removeKernelProfileLikeListener(listener: unknown): void
|
||||||
|
|
||||||
|
setBuddyProfileLike(...args: unknown[]): { result: number, errMsg: string, succCounts: number }
|
||||||
|
|
||||||
|
getBuddyProfileLike(req: BuddyProfileLikeReq): Promise<GeneralCallResult & {
|
||||||
|
'info': {
|
||||||
|
'userLikeInfos': Array<any>,
|
||||||
|
'friendMaxVotes': number,
|
||||||
|
'start': number
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
|
||||||
|
getProfileLikeScidResourceInfo(...args: unknown[]): void
|
||||||
|
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
106
src/ntqqapi/services/NodeIKernelProfileService.ts
Normal file
106
src/ntqqapi/services/NodeIKernelProfileService.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { AnyCnameRecord } from 'node:dns'
|
||||||
|
import { SimpleInfo } from '../types'
|
||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export enum UserDetailSource {
|
||||||
|
KDB,
|
||||||
|
KSERVER
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProfileBizType {
|
||||||
|
KALL,
|
||||||
|
KBASEEXTEND,
|
||||||
|
KVAS,
|
||||||
|
KQZONE,
|
||||||
|
KOTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelProfileService {
|
||||||
|
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string,string>>//uin->uid
|
||||||
|
|
||||||
|
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string,string>>
|
||||||
|
|
||||||
|
// {
|
||||||
|
// coreInfo: CoreInfo,
|
||||||
|
// baseInfo: BaseInfo,
|
||||||
|
// status: null,
|
||||||
|
// vasInfo: null,
|
||||||
|
// relationFlags: null,
|
||||||
|
// otherFlags: null,
|
||||||
|
// intimate: null
|
||||||
|
// }
|
||||||
|
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>
|
||||||
|
|
||||||
|
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>
|
||||||
|
|
||||||
|
addKernelProfileListener(listener: any): number
|
||||||
|
|
||||||
|
removeKernelProfileListener(listenerId: number): void
|
||||||
|
|
||||||
|
prepareRegionConfig(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getLocalStrangerRemark(): Promise<AnyCnameRecord>
|
||||||
|
|
||||||
|
enumCountryOptions(): Array<string>
|
||||||
|
|
||||||
|
enumProvinceOptions(Country: string): Array<string>
|
||||||
|
|
||||||
|
enumCityOptions(Country: string, Province: string): unknown
|
||||||
|
|
||||||
|
enumAreaOptions(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
//SimpleInfo
|
||||||
|
// this.uid = ""
|
||||||
|
// this.uid = str
|
||||||
|
// this.uin = j2
|
||||||
|
// this.isBuddy = z
|
||||||
|
// this.coreInfo = coreInfo
|
||||||
|
// this.baseInfo = baseInfo
|
||||||
|
// this.status = statusInfo
|
||||||
|
// this.vasInfo = vasInfo
|
||||||
|
// this.relationFlags = relationFlag
|
||||||
|
// this.otherFlags = otherFlag
|
||||||
|
// this.intimate = intimate
|
||||||
|
|
||||||
|
modifySelfProfile(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
modifyDesktopMiniProfile(param: any): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
setNickName(NickName: string): Promise<unknown>
|
||||||
|
|
||||||
|
setLongNick(longNick: string): Promise<unknown>
|
||||||
|
|
||||||
|
setBirthday(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
setGander(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
setHeader(arg: string): Promise<unknown>
|
||||||
|
|
||||||
|
setRecommendImgFlag(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
getUserSimpleInfo(force: boolean, uids: string[],): Promise<unknown>
|
||||||
|
|
||||||
|
getUserDetailInfo(uid: string): Promise<unknown>
|
||||||
|
|
||||||
|
getUserDetailInfoWithBizInfo(uid: string, Biz: any[]): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getUserDetailInfoByUin(uin: string): Promise<any>
|
||||||
|
|
||||||
|
getZplanAvatarInfos(args: string[]): Promise<unknown>
|
||||||
|
|
||||||
|
getStatus(uid: string): Promise<unknown>
|
||||||
|
|
||||||
|
startStatusPolling(isForceReset: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
getSelfStatus(): Promise<unknown>
|
||||||
|
|
||||||
|
setdisableEmojiShortCuts(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getProfileQzonePicInfo(uid: string, type: number, force: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
//profileService.getCoreInfo("UserRemarkServiceImpl::getStrangerRemarkByUid", arrayList)
|
||||||
|
getCoreInfo(name: string, arg: any[]): unknown
|
||||||
|
|
||||||
|
//m429253e12.getOtherFlag("FriendListInfoCache_getKernelDataAndPutCache", new ArrayList<>())
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
5
src/ntqqapi/services/NodeIKernelUixConvertService.ts
Normal file
5
src/ntqqapi/services/NodeIKernelUixConvertService.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface NodeIKernelUixConvertService {
|
||||||
|
getUin(uid: string[]): Promise<{ uinInfo: Map<string, string> }>
|
||||||
|
|
||||||
|
getUid(uin: string[]): Promise<{ uidInfo: Map<string, string> }>
|
||||||
|
}
|
16
src/ntqqapi/services/common.ts
Normal file
16
src/ntqqapi/services/common.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export enum GeneralCallResultStatus {
|
||||||
|
OK = 0
|
||||||
|
// ERROR = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeneralCallResult {
|
||||||
|
result: GeneralCallResultStatus
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface forceFetchClientKeyRetType extends GeneralCallResult {
|
||||||
|
url: string
|
||||||
|
keyIndex: string
|
||||||
|
clientKey: string
|
||||||
|
expireTime: string
|
||||||
|
}
|
7
src/ntqqapi/services/index.ts
Normal file
7
src/ntqqapi/services/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export * from './NodeIKernelBuddyService'
|
||||||
|
export * from './NodeIKernelProfileService'
|
||||||
|
export * from './NodeIKernelGroupService'
|
||||||
|
export * from './NodeIKernelProfileLikeService'
|
||||||
|
export * from './NodeIKernelMsgService'
|
||||||
|
export * from './NodeIKernelMSFService'
|
||||||
|
export * from './NodeIKernelUixConvertService'
|
@@ -1,5 +1,12 @@
|
|||||||
import { QQLevel, Sex } from './user'
|
import { QQLevel, Sex } from './user'
|
||||||
|
|
||||||
|
export enum GroupListUpdateType {
|
||||||
|
REFRESHALL,
|
||||||
|
GETALL,
|
||||||
|
MODIFIED,
|
||||||
|
REMOVE
|
||||||
|
}
|
||||||
|
|
||||||
export interface Group {
|
export interface Group {
|
||||||
groupCode: string
|
groupCode: string
|
||||||
maxMember: number
|
maxMember: number
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { GroupMemberRole } from './group'
|
import { GroupMemberRole } from './group'
|
||||||
import exp from 'constants'
|
|
||||||
|
|
||||||
export enum ElementType {
|
export enum ElementType {
|
||||||
TEXT = 1,
|
TEXT = 1,
|
||||||
@@ -16,13 +15,7 @@ export enum ElementType {
|
|||||||
export interface SendTextElement {
|
export interface SendTextElement {
|
||||||
elementType: ElementType.TEXT
|
elementType: ElementType.TEXT
|
||||||
elementId: ''
|
elementId: ''
|
||||||
textElement: {
|
textElement: TextElement
|
||||||
content: string
|
|
||||||
atType: number
|
|
||||||
atUid: string
|
|
||||||
atTinyId: string
|
|
||||||
atNtUid: string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendPttElement {
|
export interface SendPttElement {
|
||||||
@@ -78,12 +71,7 @@ export interface SendPicElement {
|
|||||||
export interface SendReplyElement {
|
export interface SendReplyElement {
|
||||||
elementType: ElementType.REPLY
|
elementType: ElementType.REPLY
|
||||||
elementId: ''
|
elementId: ''
|
||||||
replyElement: {
|
replyElement: ReplyElement
|
||||||
replayMsgSeq: string
|
|
||||||
replayMsgId: string
|
|
||||||
senderUin: string
|
|
||||||
senderUinStr: string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendFaceElement {
|
export interface SendFaceElement {
|
||||||
@@ -97,6 +85,21 @@ export interface SendMarketFaceElement {
|
|||||||
marketFaceElement: MarketFaceElement
|
marketFaceElement: MarketFaceElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TextElement {
|
||||||
|
content: string
|
||||||
|
atType: number
|
||||||
|
atUid: string
|
||||||
|
atTinyId: string
|
||||||
|
atNtUid: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReplyElement {
|
||||||
|
replayMsgSeq: string
|
||||||
|
replayMsgId: string
|
||||||
|
senderUin: string
|
||||||
|
senderUinStr: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface FileElement {
|
export interface FileElement {
|
||||||
fileMd5?: ''
|
fileMd5?: ''
|
||||||
fileName: string
|
fileName: string
|
||||||
@@ -188,6 +191,7 @@ export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn'
|
|||||||
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn'
|
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn'
|
||||||
|
|
||||||
export interface PicElement {
|
export interface PicElement {
|
||||||
|
picSubType: PicSubType
|
||||||
picType: PicType // 有这玩意儿吗
|
picType: PicType // 有这玩意儿吗
|
||||||
originImageUrl: string // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
originImageUrl: string // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
||||||
originImageMd5?: string
|
originImageMd5?: string
|
||||||
@@ -226,6 +230,7 @@ export interface GrayTipElement {
|
|||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
jsonGrayTipElement: {
|
jsonGrayTipElement: {
|
||||||
|
busiId: number
|
||||||
jsonStr: string
|
jsonStr: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,6 +381,7 @@ export interface RawMessage {
|
|||||||
msgShortId?: number // 自己维护的消息id
|
msgShortId?: number // 自己维护的消息id
|
||||||
msgTime: string // 时间戳,秒
|
msgTime: string // 时间戳,秒
|
||||||
msgSeq: string
|
msgSeq: string
|
||||||
|
msgRandom: string
|
||||||
senderUid: string
|
senderUid: string
|
||||||
senderUin?: string // 发送者QQ号
|
senderUin?: string // 发送者QQ号
|
||||||
peerUid: string // 群号 或者 QQ uid
|
peerUid: string // 群号 或者 QQ uid
|
||||||
@@ -413,3 +419,43 @@ export interface RawMessage {
|
|||||||
multiForwardMsgElement: MultiForwardMsgElement
|
multiForwardMsgElement: MultiForwardMsgElement
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Peer {
|
||||||
|
chatType: ChatType
|
||||||
|
peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
||||||
|
guildId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageElement {
|
||||||
|
elementType: ElementType
|
||||||
|
elementId: string
|
||||||
|
extBufForUI: string //"0x"
|
||||||
|
textElement?: TextElement
|
||||||
|
faceElement?: FaceElement
|
||||||
|
marketFaceElement?: MarkdownElement
|
||||||
|
replyElement?: ReplyElement
|
||||||
|
picElement?: PicElement
|
||||||
|
pttElement?: PttElement
|
||||||
|
videoElement?: VideoElement
|
||||||
|
grayTipElement?: GrayTipElement
|
||||||
|
arkElement?: ArkElement
|
||||||
|
fileElement?: FileElement
|
||||||
|
liveGiftElement?: null
|
||||||
|
markdownElement?: MarkdownElement
|
||||||
|
structLongMsgElement?: any
|
||||||
|
multiForwardMsgElement?: MultiForwardMsgElement
|
||||||
|
giphyElement?: any
|
||||||
|
walletElement?: null
|
||||||
|
inlineKeyboardElement?: InlineKeyboardElement
|
||||||
|
textGiftElement?: null //????
|
||||||
|
calendarElement?: any
|
||||||
|
yoloGameResultElement?: any
|
||||||
|
avRecordElement?: any
|
||||||
|
structMsgElement?: null
|
||||||
|
faceBubbleElement?: any
|
||||||
|
shareLocationElement?: any
|
||||||
|
tofuRecordElement?: any
|
||||||
|
taskTopMsgElement?: any
|
||||||
|
recommendedMsgElement?: any
|
||||||
|
actionBarElement?: any
|
||||||
|
}
|
@@ -64,3 +64,41 @@ export interface FriendRequestNotify {
|
|||||||
buddyReqs: FriendRequest[]
|
buddyReqs: FriendRequest[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum MemberExtSourceType {
|
||||||
|
DEFAULTTYPE = 0,
|
||||||
|
TITLETYPE = 1,
|
||||||
|
NEWGROUPTYPE = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupExtParam {
|
||||||
|
groupCode: string
|
||||||
|
seq: string
|
||||||
|
beginUin: string
|
||||||
|
dataTime: string
|
||||||
|
uinList: Array<string>
|
||||||
|
uinNum: string
|
||||||
|
groupType: string
|
||||||
|
richCardNameVer: string
|
||||||
|
sourceType: MemberExtSourceType
|
||||||
|
memberExtFilter: {
|
||||||
|
memberLevelInfoUin: number
|
||||||
|
memberLevelInfoPoint: number
|
||||||
|
memberLevelInfoActiveDay: number
|
||||||
|
memberLevelInfoLevel: number
|
||||||
|
memberLevelInfoName: number
|
||||||
|
levelName: number
|
||||||
|
dataTime: number
|
||||||
|
userShowFlag: number
|
||||||
|
sysShowFlag: number
|
||||||
|
timeToUpdate: number
|
||||||
|
nickName: number
|
||||||
|
specialTitle: number
|
||||||
|
levelNameNew: number
|
||||||
|
userShowFlagNew: number
|
||||||
|
msgNeedField: number
|
||||||
|
cmdUinFlagExt3Grocery: number
|
||||||
|
memberIcon: number
|
||||||
|
memberInfoSeq: number
|
||||||
|
}
|
||||||
|
}
|
@@ -77,8 +77,267 @@ export interface Friend extends User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryFriend {
|
export interface CategoryFriend {
|
||||||
categoryId: number;
|
categoryId: number
|
||||||
categroyName: string;
|
categroyName: string
|
||||||
categroyMbCount: number;
|
categroyMbCount: number
|
||||||
buddyList: User[]
|
buddyList: User[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CoreInfo {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
nick: string
|
||||||
|
remark: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseInfo {
|
||||||
|
qid: string
|
||||||
|
longNick: string
|
||||||
|
birthday_year: number
|
||||||
|
birthday_month: number
|
||||||
|
birthday_day: number
|
||||||
|
age: number
|
||||||
|
sex: number
|
||||||
|
eMail: string
|
||||||
|
phoneNum: string
|
||||||
|
categoryId: number
|
||||||
|
richTime: number
|
||||||
|
richBuffer: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MusicInfo {
|
||||||
|
buf: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoBizInfo {
|
||||||
|
cid: string
|
||||||
|
tvUrl: string
|
||||||
|
synchType: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoInfo {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtOnlineBusinessInfo {
|
||||||
|
buf: string
|
||||||
|
customStatus: any
|
||||||
|
videoBizInfo: VideoBizInfo
|
||||||
|
videoInfo: VideoInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtBuffer {
|
||||||
|
buf: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserStatus {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
status: number
|
||||||
|
extStatus: number
|
||||||
|
batteryStatus: number
|
||||||
|
termType: number
|
||||||
|
netType: number
|
||||||
|
iconType: number
|
||||||
|
customStatus: any
|
||||||
|
setTime: string
|
||||||
|
specialFlag: number
|
||||||
|
abiFlag: number
|
||||||
|
eNetworkType: number
|
||||||
|
showName: string
|
||||||
|
termDesc: string
|
||||||
|
musicInfo: MusicInfo
|
||||||
|
extOnlineBusinessInfo: ExtOnlineBusinessInfo
|
||||||
|
extBuffer: ExtBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PrivilegeIcon {
|
||||||
|
jumpUrl: string
|
||||||
|
openIconList: any[]
|
||||||
|
closeIconList: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VasInfo {
|
||||||
|
vipFlag: boolean
|
||||||
|
yearVipFlag: boolean
|
||||||
|
svipFlag: boolean
|
||||||
|
vipLevel: number
|
||||||
|
bigClub: boolean
|
||||||
|
bigClubLevel: number
|
||||||
|
nameplateVipType: number
|
||||||
|
grayNameplateFlag: number
|
||||||
|
superVipTemplateId: number
|
||||||
|
diyFontId: number
|
||||||
|
pendantId: number
|
||||||
|
pendantDiyId: number
|
||||||
|
faceId: number
|
||||||
|
vipFont: number
|
||||||
|
vipFontType: number
|
||||||
|
magicFont: number
|
||||||
|
fontEffect: number
|
||||||
|
newLoverDiamondFlag: number
|
||||||
|
extendNameplateId: number
|
||||||
|
diyNameplateIDs: any[]
|
||||||
|
vipStartFlag: number
|
||||||
|
vipDataFlag: number
|
||||||
|
gameNameplateId: string
|
||||||
|
gameLastLoginTime: string
|
||||||
|
gameRank: number
|
||||||
|
gameIconShowFlag: boolean
|
||||||
|
gameCardId: string
|
||||||
|
vipNameColorId: string
|
||||||
|
privilegeIcon: PrivilegeIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SimpleInfo {
|
||||||
|
uid?: string
|
||||||
|
uin?: string
|
||||||
|
coreInfo: CoreInfo
|
||||||
|
baseInfo: BaseInfo
|
||||||
|
status: UserStatus | null
|
||||||
|
vasInfo: VasInfo | null
|
||||||
|
relationFlags: RelationFlags | null
|
||||||
|
otherFlags: any | null
|
||||||
|
intimate: any | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelationFlags {
|
||||||
|
topTime: string
|
||||||
|
isBlock: boolean
|
||||||
|
isMsgDisturb: boolean
|
||||||
|
isSpecialCareOpen: boolean
|
||||||
|
isSpecialCareZone: boolean
|
||||||
|
ringId: string
|
||||||
|
isBlocked: boolean
|
||||||
|
recommendImgFlag: number
|
||||||
|
disableEmojiShortCuts: number
|
||||||
|
qidianMasterFlag: number
|
||||||
|
qidianCrewFlag: number
|
||||||
|
qidianCrewFlag2: number
|
||||||
|
isHideQQLevel: number
|
||||||
|
isHidePrivilegeIcon: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FriendV2 extends SimpleInfo {
|
||||||
|
categoryId?: number
|
||||||
|
categroyName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommonExt {
|
||||||
|
constellation: number
|
||||||
|
shengXiao: number
|
||||||
|
kBloodType: number
|
||||||
|
homeTown: string
|
||||||
|
makeFriendCareer: number
|
||||||
|
pos: string
|
||||||
|
college: string
|
||||||
|
country: string
|
||||||
|
province: string
|
||||||
|
city: string
|
||||||
|
postCode: string
|
||||||
|
address: string
|
||||||
|
regTime: number
|
||||||
|
interest: string
|
||||||
|
labels: any[]
|
||||||
|
qqLevel: QQLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Pic {
|
||||||
|
picId: string
|
||||||
|
picTime: number
|
||||||
|
picUrlMap: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PhotoWall {
|
||||||
|
picList: Pic[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserDetailInfoListenerArg {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
simpleInfo: SimpleInfo
|
||||||
|
commonExt: CommonExt
|
||||||
|
photoWall: PhotoWall
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuddyProfileLikeReq {
|
||||||
|
friendUids: string[]
|
||||||
|
basic: number
|
||||||
|
vote: number
|
||||||
|
favorite: number
|
||||||
|
userProfile: number
|
||||||
|
type: number
|
||||||
|
start: number
|
||||||
|
limit: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserDetailInfoByUinV2 {
|
||||||
|
result: number
|
||||||
|
errMsg: string
|
||||||
|
detail: {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
simpleInfo: SimpleInfo
|
||||||
|
commonExt: CommonExt
|
||||||
|
photoWall: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserDetailInfoByUin {
|
||||||
|
result: number
|
||||||
|
errMsg: string
|
||||||
|
info: {
|
||||||
|
uid: string //这个没办法用
|
||||||
|
qid: string
|
||||||
|
uin: string
|
||||||
|
nick: string
|
||||||
|
remark: string
|
||||||
|
longNick: string
|
||||||
|
avatarUrl: string
|
||||||
|
birthday_year: number
|
||||||
|
birthday_month: number
|
||||||
|
birthday_day: number
|
||||||
|
sex: number //0
|
||||||
|
topTime: string
|
||||||
|
constellation: number
|
||||||
|
shengXiao: number
|
||||||
|
kBloodType: number
|
||||||
|
homeTown: string
|
||||||
|
makeFriendCareer: number
|
||||||
|
pos: string
|
||||||
|
eMail: string
|
||||||
|
phoneNum: string
|
||||||
|
college: string
|
||||||
|
country: string
|
||||||
|
province: string
|
||||||
|
city: string
|
||||||
|
postCode: string
|
||||||
|
address: string
|
||||||
|
isBlock: boolean
|
||||||
|
isSpecialCareOpen: boolean
|
||||||
|
isSpecialCareZone: boolean
|
||||||
|
ringId: string
|
||||||
|
regTime: number
|
||||||
|
interest: string
|
||||||
|
termType: number
|
||||||
|
labels: any[]
|
||||||
|
qqLevel: { crownNum: number, sunNum: number, moonNum: number, starNum: number }
|
||||||
|
isHideQQLevel: number
|
||||||
|
privilegeIcon: { jumpUrl: string, openIconList: any[], closeIconList: any[] }
|
||||||
|
isHidePrivilegeIcon: number
|
||||||
|
photoWall: { picList: any[] }
|
||||||
|
vipFlag: boolean
|
||||||
|
yearVipFlag: boolean
|
||||||
|
svipFlag: boolean
|
||||||
|
vipLevel: number
|
||||||
|
status: number
|
||||||
|
qidianMasterFlag: number
|
||||||
|
qidianCrewFlag: number
|
||||||
|
qidianCrewFlag2: number
|
||||||
|
extStatus: number
|
||||||
|
recommendImgFlag: number
|
||||||
|
disableEmojiShortCuts: number
|
||||||
|
pendantId: string
|
||||||
|
vipNameColorId: string
|
||||||
|
}
|
||||||
|
}
|
86
src/ntqqapi/wrapper.ts
Normal file
86
src/ntqqapi/wrapper.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
NodeIKernelBuddyService,
|
||||||
|
NodeIKernelGroupService,
|
||||||
|
NodeIKernelProfileService,
|
||||||
|
NodeIKernelProfileLikeService,
|
||||||
|
NodeIKernelMSFService,
|
||||||
|
NodeIKernelMsgService,
|
||||||
|
NodeIKernelUixConvertService
|
||||||
|
} from './services'
|
||||||
|
import os from 'node:os'
|
||||||
|
const Process = require('node:process')
|
||||||
|
|
||||||
|
export interface NodeIQQNTWrapperSession {
|
||||||
|
[key: string]: any
|
||||||
|
getBuddyService(): NodeIKernelBuddyService
|
||||||
|
getGroupService(): NodeIKernelGroupService
|
||||||
|
getProfileService(): NodeIKernelProfileService
|
||||||
|
getProfileLikeService(): NodeIKernelProfileLikeService
|
||||||
|
getMsgService(): NodeIKernelMsgService
|
||||||
|
getMSFService(): NodeIKernelMSFService
|
||||||
|
getUixConvertService(): NodeIKernelUixConvertService
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WrapperApi {
|
||||||
|
NodeIQQNTWrapperSession?: NodeIQQNTWrapperSession
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WrapperConstructor {
|
||||||
|
[key: string]: any
|
||||||
|
NodeIKernelBuddyListener?: any
|
||||||
|
NodeIKernelGroupListener?: any
|
||||||
|
NodeQQNTWrapperUtil?: any
|
||||||
|
NodeIKernelMsgListener?: any
|
||||||
|
NodeIQQNTWrapperEngine?: any
|
||||||
|
NodeIGlobalAdapter?: any
|
||||||
|
NodeIDependsAdapter?: any
|
||||||
|
NodeIDispatcherAdapter?: any
|
||||||
|
NodeIKernelSessionListener?: any
|
||||||
|
NodeIKernelLoginService?: any
|
||||||
|
NodeIKernelLoginListener?: any
|
||||||
|
NodeIKernelProfileService?: any
|
||||||
|
NodeIKernelProfileListener?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapperApi: WrapperApi = {}
|
||||||
|
|
||||||
|
export const wrapperConstructor: WrapperConstructor = {}
|
||||||
|
|
||||||
|
const constructor = [
|
||||||
|
'NodeIKernelBuddyListener',
|
||||||
|
'NodeIKernelGroupListener',
|
||||||
|
'NodeQQNTWrapperUtil',
|
||||||
|
'NodeIKernelMsgListener',
|
||||||
|
'NodeIQQNTWrapperEngine',
|
||||||
|
'NodeIGlobalAdapter',
|
||||||
|
'NodeIDependsAdapter',
|
||||||
|
'NodeIDispatcherAdapter',
|
||||||
|
'NodeIKernelSessionListener',
|
||||||
|
'NodeIKernelLoginService',
|
||||||
|
'NodeIKernelLoginListener',
|
||||||
|
'NodeIKernelProfileService',
|
||||||
|
'NodeIKernelProfileListener',
|
||||||
|
]
|
||||||
|
|
||||||
|
Process.dlopenOrig = Process.dlopen
|
||||||
|
|
||||||
|
Process.dlopen = function (module, filename, flags = os.constants.dlopen.RTLD_LAZY) {
|
||||||
|
const dlopenRet = this.dlopenOrig(module, filename, flags)
|
||||||
|
for (let export_name in module.exports) {
|
||||||
|
module.exports[export_name] = new Proxy(module.exports[export_name], {
|
||||||
|
construct: (target, args, _newTarget) => {
|
||||||
|
const ret = new target(...args)
|
||||||
|
if (export_name === 'NodeIQQNTWrapperSession') wrapperApi.NodeIQQNTWrapperSession = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (constructor.includes(export_name)) {
|
||||||
|
wrapperConstructor[export_name] = module.exports[export_name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dlopenRet
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSession() {
|
||||||
|
return wrapperApi['NodeIQQNTWrapperSession']
|
||||||
|
}
|
@@ -4,8 +4,8 @@ import { OB11Return } from '../types'
|
|||||||
|
|
||||||
import { log } from '../../common/utils/log'
|
import { log } from '../../common/utils/log'
|
||||||
|
|
||||||
class BaseAction<PayloadType, ReturnDataType> {
|
abstract class BaseAction<PayloadType, ReturnDataType> {
|
||||||
actionName: ActionName
|
abstract actionName: ActionName
|
||||||
|
|
||||||
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
|
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
|
||||||
return {
|
return {
|
||||||
@@ -21,7 +21,7 @@ class BaseAction<PayloadType, ReturnDataType> {
|
|||||||
try {
|
try {
|
||||||
const resData = await this._handle(payload)
|
const resData = await this._handle(payload)
|
||||||
return OB11Response.ok(resData)
|
return OB11Response.ok(resData)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('发生错误', e)
|
log('发生错误', e)
|
||||||
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200)
|
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200)
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ class BaseAction<PayloadType, ReturnDataType> {
|
|||||||
try {
|
try {
|
||||||
const resData = await this._handle(payload)
|
const resData = await this._handle(payload)
|
||||||
return OB11Response.ok(resData, echo)
|
return OB11Response.ok(resData, echo)
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('发生错误', e)
|
log('发生错误', e)
|
||||||
return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo)
|
return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo)
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import BaseAction from '../BaseAction'
|
|||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import { dbUtil } from '@/common/db'
|
import { dbUtil } from '@/common/db'
|
||||||
import { getConfigUtil } from '@/common/config'
|
import { getConfigUtil } from '@/common/config'
|
||||||
import { log, sleep, uri2local } from '@/common/utils'
|
import { checkFileReceived, log, sleep, uri2local } from '@/common/utils'
|
||||||
import { NTQQFileApi } from '@/ntqqapi/api'
|
import { NTQQFileApi } from '@/ntqqapi/api'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { FileElement, RawMessage, VideoElement } from '@/ntqqapi/types'
|
import { FileElement, RawMessage, VideoElement } from '@/ntqqapi/types'
|
||||||
@@ -20,7 +20,7 @@ export interface GetFileResponse {
|
|||||||
base64?: string
|
base64?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||||
private getElement(msg: RawMessage, elementId: string): VideoElement | FileElement {
|
private getElement(msg: RawMessage, elementId: string): VideoElement | FileElement {
|
||||||
let element = msg.elements.find((e) => e.elementId === elementId)
|
let element = msg.elements.find((e) => e.elementId === elementId)
|
||||||
if (!element) {
|
if (!element) {
|
||||||
@@ -38,20 +38,21 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
log('找到了文件 element', element)
|
log('找到了文件 element', element)
|
||||||
// 构建下载函数
|
// 构建下载函数
|
||||||
await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, cache.elementId, '', '', true)
|
await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, cache.elementId, '', '', true)
|
||||||
await sleep(1000) // 这里延时是为何?
|
// 等待文件下载完成
|
||||||
msg = await dbUtil.getMsgByLongId(cache.msgId)
|
msg = await dbUtil.getMsgByLongId(cache.msgId)
|
||||||
log('下载完成后的msg', msg)
|
log('下载完成后的msg', msg)
|
||||||
cache.filePath = this.getElement(msg, cache.elementId).filePath
|
cache.filePath = this.getElement(msg!, cache.elementId).filePath
|
||||||
|
await checkFileReceived(cache.filePath, 10 * 1000)
|
||||||
dbUtil.addFileCache(file, cache).then()
|
dbUtil.addFileCache(file, cache).then()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
||||||
const cache = await dbUtil.getFileCache(payload.file)
|
let cache = await dbUtil.getFileCache(payload.file)
|
||||||
const { autoDeleteFile, enableLocalFile2Url, autoDeleteFileSecond } = getConfigUtil().getConfig()
|
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
throw new Error('file not found')
|
throw new Error('file not found')
|
||||||
}
|
}
|
||||||
|
const { autoDeleteFile, enableLocalFile2Url, autoDeleteFileSecond } = getConfigUtil().getConfig()
|
||||||
if (cache.downloadFunc) {
|
if (cache.downloadFunc) {
|
||||||
await cache.downloadFunc()
|
await cache.downloadFunc()
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'
|
import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
|
import {decodeSilk} from "@/common/utils/audio";
|
||||||
|
import { getConfigUtil } from '@/common/config'
|
||||||
|
import path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
interface Payload extends GetFilePayload {
|
interface Payload extends GetFilePayload {
|
||||||
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
||||||
@@ -9,7 +13,13 @@ export default class GetRecord extends GetFileBase {
|
|||||||
actionName = ActionName.GetRecord
|
actionName = ActionName.GetRecord
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<GetFileResponse> {
|
protected async _handle(payload: Payload): Promise<GetFileResponse> {
|
||||||
let res = super._handle(payload)
|
let res = await super._handle(payload)
|
||||||
|
res.file = await decodeSilk(res.file!, payload.out_format)
|
||||||
|
res.file_name = path.basename(res.file)
|
||||||
|
res.file_size = fs.statSync(res.file).size.toString()
|
||||||
|
if (getConfigUtil().getConfig().enableLocalFile2Url){
|
||||||
|
res.base64 = fs.readFileSync(res.file, 'base64')
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
src/onebot11/action/go-cqhttp/DelEssenceMsg.ts
Normal file
24
src/onebot11/action/go-cqhttp/DelEssenceMsg.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { NTQQGroupApi } from '../../../ntqqapi/api/group'
|
||||||
|
import { dbUtil } from '@/common/db';
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
message_id: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GoCQHTTPDelEssenceMsg extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_DelEssenceMsg;
|
||||||
|
|
||||||
|
protected async _handle(payload: Payload): Promise<any> {
|
||||||
|
const msg = await dbUtil.getMsgByShortId(parseInt(payload.message_id.toString()));
|
||||||
|
if (!msg) {
|
||||||
|
throw new Error('msg not found');
|
||||||
|
}
|
||||||
|
return await NTQQGroupApi.removeGroupEssence(
|
||||||
|
msg.peerUid,
|
||||||
|
msg.msgId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@ import { ActionName } from '../types'
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { join as joinPath } from 'node:path'
|
import { join as joinPath } from 'node:path'
|
||||||
import { calculateFileMD5, httpDownload, TEMP_DIR } from '../../../common/utils'
|
import { calculateFileMD5, httpDownload, TEMP_DIR } from '../../../common/utils'
|
||||||
import { v4 as uuid4 } from 'uuid'
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
thread_count?: number
|
thread_count?: number
|
||||||
@@ -22,7 +22,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
|
|||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<FileResponse> {
|
protected async _handle(payload: Payload): Promise<FileResponse> {
|
||||||
const isRandomName = !payload.name
|
const isRandomName = !payload.name
|
||||||
let name = payload.name || uuid4()
|
let name = payload.name || randomUUID()
|
||||||
const filePath = joinPath(TEMP_DIR, name)
|
const filePath = joinPath(TEMP_DIR, name)
|
||||||
|
|
||||||
if (payload.base64) {
|
if (payload.base64) {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types'
|
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types'
|
||||||
import { NTQQMsgApi, Peer } from '../../../ntqqapi/api'
|
import { NTQQMsgApi } from '@/ntqqapi/api'
|
||||||
import { dbUtil } from '../../../common/db'
|
import { dbUtil } from '../../../common/db'
|
||||||
import { OB11Constructor } from '../../constructor'
|
import { OB11Constructor } from '../../constructor'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
@@ -37,12 +37,13 @@ export class GoCQHTTGetForwardMsgAction extends BaseAction<Payload, any> {
|
|||||||
let messages = await Promise.all(
|
let messages = await Promise.all(
|
||||||
msgList.map(async (msg) => {
|
msgList.map(async (msg) => {
|
||||||
let resMsg = await OB11Constructor.message(msg)
|
let resMsg = await OB11Constructor.message(msg)
|
||||||
resMsg.message_id = await dbUtil.addMsg(msg)
|
resMsg.message_id = (await dbUtil.addMsg(msg))!
|
||||||
return resMsg
|
return resMsg
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
messages.map((msg) => {
|
messages.map(v => {
|
||||||
;(<OB11ForwardMessage>msg).content = msg.message
|
const msg = v as Partial<OB11ForwardMessage>
|
||||||
|
msg.content = msg.message
|
||||||
delete msg.message
|
delete msg.message
|
||||||
})
|
})
|
||||||
return { messages }
|
return { messages }
|
||||||
|
@@ -6,7 +6,6 @@ import { ChatType } from '../../../ntqqapi/types'
|
|||||||
import { dbUtil } from '../../../common/db'
|
import { dbUtil } from '../../../common/db'
|
||||||
import { NTQQMsgApi } from '../../../ntqqapi/api/msg'
|
import { NTQQMsgApi } from '../../../ntqqapi/api/msg'
|
||||||
import { OB11Constructor } from '../../constructor'
|
import { OB11Constructor } from '../../constructor'
|
||||||
import { log } from '../../../common/utils'
|
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
group_id: number
|
group_id: number
|
||||||
|
23
src/onebot11/action/go-cqhttp/SetEssenceMsg.ts
Normal file
23
src/onebot11/action/go-cqhttp/SetEssenceMsg.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { NTQQGroupApi } from '../../../ntqqapi/api/group'
|
||||||
|
import { dbUtil } from '@/common/db';
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
message_id: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GoCQHTTPSetEssenceMsg extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_SetEssenceMsg;
|
||||||
|
|
||||||
|
protected async _handle(payload: Payload): Promise<any> {
|
||||||
|
const msg = await dbUtil.getMsgByShortId(parseInt(payload.message_id.toString()));
|
||||||
|
if (!msg) {
|
||||||
|
throw new Error('msg not found');
|
||||||
|
}
|
||||||
|
return await NTQQGroupApi.addGroupEssence(
|
||||||
|
msg.peerUid,
|
||||||
|
msg.msgId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,12 @@
|
|||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { getGroup, getUidByUin } from '../../../common/data'
|
import { getGroup, getUidByUin } from '@/common/data'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { SendMsgElementConstructor } from '../../../ntqqapi/constructor'
|
import { SendMsgElementConstructor } from '@/ntqqapi/constructor'
|
||||||
import { ChatType, SendFileElement } from '../../../ntqqapi/types'
|
import { ChatType, SendFileElement } from '@/ntqqapi/types'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { NTQQMsgApi, Peer } from '../../../ntqqapi/api/msg'
|
import { NTQQMsgApi } from '@/ntqqapi/api/msg'
|
||||||
import { uri2local } from '../../../common/utils'
|
import { uri2local } from '@/common/utils'
|
||||||
|
import { Peer } from '@/ntqqapi/types'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
user_id: number
|
user_id: number
|
||||||
@@ -20,9 +21,9 @@ class GoCQHTTPUploadFileBase extends BaseAction<Payload, null> {
|
|||||||
|
|
||||||
getPeer(payload: Payload): Peer {
|
getPeer(payload: Payload): Peer {
|
||||||
if (payload.user_id) {
|
if (payload.user_id) {
|
||||||
return { chatType: ChatType.friend, peerUid: getUidByUin(payload.user_id.toString()) }
|
return { chatType: ChatType.friend, peerUid: getUidByUin(payload.user_id.toString())! }
|
||||||
}
|
}
|
||||||
return { chatType: ChatType.group, peerUid: payload.group_id.toString() }
|
return { chatType: ChatType.group, peerUid: payload.group_id?.toString()! }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<null> {
|
protected async _handle(payload: Payload): Promise<null> {
|
||||||
|
@@ -1,24 +1,24 @@
|
|||||||
import { GroupEssenceMsgRet, WebApi } from "@/ntqqapi/api";
|
import { GroupEssenceMsgRet, WebApi } from '@/ntqqapi/api'
|
||||||
import BaseAction from "../BaseAction";
|
import BaseAction from '../BaseAction'
|
||||||
import { ActionName } from "../types";
|
import { ActionName } from '../types'
|
||||||
|
|
||||||
interface PayloadType {
|
interface PayloadType {
|
||||||
group_id: number;
|
group_id: number
|
||||||
pages?: number;
|
pages?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GetGroupEssence extends BaseAction<PayloadType, GroupEssenceMsgRet> {
|
export class GetGroupEssence extends BaseAction<PayloadType, GroupEssenceMsgRet | void> {
|
||||||
actionName = ActionName.GoCQHTTP_GetEssenceMsg;
|
actionName = ActionName.GoCQHTTP_GetEssenceMsg
|
||||||
|
|
||||||
protected async _handle(payload: PayloadType) {
|
protected async _handle(payload: PayloadType) {
|
||||||
throw '此 api 暂不支持'
|
throw '此 api 暂不支持'
|
||||||
const ret = await WebApi.getGroupEssenceMsg(payload.group_id.toString(), payload.pages?.toString() || '0');
|
const ret = await WebApi.getGroupEssenceMsg(payload.group_id.toString(), payload.pages?.toString() || '0')
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error('获取失败');
|
throw new Error('获取失败')
|
||||||
}
|
}
|
||||||
// ret.map((item) => {
|
// ret.map((item) => {
|
||||||
//
|
//
|
||||||
// })
|
// })
|
||||||
return ret;
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +1,23 @@
|
|||||||
import { WebApi, WebHonorType } from "@/ntqqapi/api";
|
import { WebApi, WebHonorType } from '@/ntqqapi/api'
|
||||||
import { ActionName } from "../types";
|
import { ActionName } from '../types'
|
||||||
import BaseAction from "../BaseAction";
|
import BaseAction from '../BaseAction'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
group_id: number,
|
group_id: number
|
||||||
type?: WebHonorType
|
type?: WebHonorType
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
|
export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
|
||||||
actionName = ActionName.GetGroupHonorInfo;
|
actionName = ActionName.GetGroupHonorInfo
|
||||||
|
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
// console.log(await NTQQUserApi.getRobotUinRange());
|
// console.log(await NTQQUserApi.getRobotUinRange())
|
||||||
if (!payload.group_id) {
|
if (!payload.group_id) {
|
||||||
throw '缺少参数group_id';
|
throw '缺少参数group_id'
|
||||||
}
|
}
|
||||||
if (!payload.type) {
|
if (!payload.type) {
|
||||||
payload.type = WebHonorType.ALL;
|
payload.type = WebHonorType.ALL
|
||||||
}
|
}
|
||||||
return await WebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
|
return await WebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,8 @@ class GetGroupMemberList extends BaseAction<PayloadType, OB11GroupMember[]> {
|
|||||||
const group = await getGroup(payload.group_id.toString())
|
const group = await getGroup(payload.group_id.toString())
|
||||||
if (group) {
|
if (group) {
|
||||||
if (!group.members?.length || payload.no_cache === true || payload.no_cache === 'true') {
|
if (!group.members?.length || payload.no_cache === true || payload.no_cache === 'true') {
|
||||||
group.members = await NTQQGroupApi.getGroupMembers(payload.group_id.toString())
|
const members = await NTQQGroupApi.getGroupMembers(payload.group_id.toString())
|
||||||
|
group.members = Array.from(members.values())
|
||||||
log('强制刷新群成员列表, 数量: ', group.members.length)
|
log('强制刷新群成员列表, 数量: ', group.members.length)
|
||||||
}
|
}
|
||||||
return OB11Constructor.groupMembers(group)
|
return OB11Constructor.groupMembers(group)
|
||||||
|
@@ -2,13 +2,11 @@ import SendMsg from '../msg/SendMsg'
|
|||||||
import { ActionName, BaseCheckResult } from '../types'
|
import { ActionName, BaseCheckResult } from '../types'
|
||||||
import { OB11PostSendMsg } from '../../types'
|
import { OB11PostSendMsg } from '../../types'
|
||||||
|
|
||||||
import { log } from '../../../common/utils/log'
|
|
||||||
|
|
||||||
class SendGroupMsg extends SendMsg {
|
class SendGroupMsg extends SendMsg {
|
||||||
actionName = ActionName.SendGroupMsg
|
actionName = ActionName.SendGroupMsg
|
||||||
|
|
||||||
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
|
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
|
||||||
delete payload.user_id
|
delete (payload as Partial<OB11PostSendMsg>).user_id
|
||||||
payload.message_type = 'group'
|
payload.message_type = 'group'
|
||||||
return super.check(payload)
|
return super.check(payload)
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,10 @@ import { ForwardFriendSingleMsg, ForwardGroupSingleMsg } from './msg/ForwardSing
|
|||||||
import { GetGroupEssence } from './group/GetGroupEssence'
|
import { GetGroupEssence } from './group/GetGroupEssence'
|
||||||
import { GetGroupHonorInfo } from './group/GetGroupHonorInfo'
|
import { GetGroupHonorInfo } from './group/GetGroupHonorInfo'
|
||||||
import { GoCQHTTHandleQuickOperation } from './go-cqhttp/QuickOperation'
|
import { GoCQHTTHandleQuickOperation } from './go-cqhttp/QuickOperation'
|
||||||
|
import GoCQHTTPSetEssenceMsg from './go-cqhttp/SetEssenceMsg'
|
||||||
|
import GoCQHTTPDelEssenceMsg from './go-cqhttp/DelEssenceMsg'
|
||||||
|
import GetEvent from './llonebot/GetEvent'
|
||||||
|
|
||||||
|
|
||||||
export const actionHandlers = [
|
export const actionHandlers = [
|
||||||
new GetFile(),
|
new GetFile(),
|
||||||
@@ -59,6 +63,7 @@ export const actionHandlers = [
|
|||||||
new GetGroupAddRequest(),
|
new GetGroupAddRequest(),
|
||||||
new SetQQAvatar(),
|
new SetQQAvatar(),
|
||||||
new GetFriendWithCategory(),
|
new GetFriendWithCategory(),
|
||||||
|
new GetEvent(),
|
||||||
// onebot11
|
// onebot11
|
||||||
new SendLike(),
|
new SendLike(),
|
||||||
new GetMsg(),
|
new GetMsg(),
|
||||||
@@ -106,7 +111,9 @@ export const actionHandlers = [
|
|||||||
new GoCQHTTPUploadPrivateFile(),
|
new GoCQHTTPUploadPrivateFile(),
|
||||||
new GoCQHTTPGetGroupMsgHistory(),
|
new GoCQHTTPGetGroupMsgHistory(),
|
||||||
new GoCQHTTGetForwardMsgAction(),
|
new GoCQHTTGetForwardMsgAction(),
|
||||||
new GoCQHTTHandleQuickOperation()
|
new GoCQHTTHandleQuickOperation(),
|
||||||
|
new GoCQHTTPSetEssenceMsg(),
|
||||||
|
new GoCQHTTPDelEssenceMsg()
|
||||||
]
|
]
|
||||||
|
|
||||||
function initActionMap() {
|
function initActionMap() {
|
||||||
|
23
src/onebot11/action/llonebot/GetEvent.ts
Normal file
23
src/onebot11/action/llonebot/GetEvent.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import BaseAction from '../BaseAction'
|
||||||
|
import { ActionName } from '../types'
|
||||||
|
import { getHttpEvent } from '../../server/event-for-http'
|
||||||
|
import { PostEventType } from '../../server/post-ob11-event'
|
||||||
|
// import { log } from "../../../common/utils";
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
key: string
|
||||||
|
timeout: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GetEvent extends BaseAction<Payload, PostEventType[]> {
|
||||||
|
actionName = ActionName.GetEvent
|
||||||
|
protected async _handle(payload: Payload): Promise<PostEventType[]> {
|
||||||
|
let key = ''
|
||||||
|
if (payload.key) {
|
||||||
|
key = payload.key;
|
||||||
|
}
|
||||||
|
let timeout = parseInt(payload.timeout?.toString()) || 0;
|
||||||
|
let evts = await getHttpEvent(key,timeout);
|
||||||
|
return evts;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,9 +1,10 @@
|
|||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { NTQQMsgApi, Peer } from '../../../ntqqapi/api'
|
import { NTQQMsgApi } from '@/ntqqapi/api'
|
||||||
import { ChatType, RawMessage } from '../../../ntqqapi/types'
|
import { ChatType, RawMessage } from '@/ntqqapi/types'
|
||||||
import { dbUtil } from '../../../common/db'
|
import { dbUtil } from '@/common/db'
|
||||||
import { getUidByUin } from '../../../common/data'
|
import { getUidByUin } from '@/common/data'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
|
import { Peer } from '@/ntqqapi/types'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
message_id: number
|
message_id: number
|
||||||
@@ -15,16 +16,16 @@ interface Response {
|
|||||||
message_id: number
|
message_id: number
|
||||||
}
|
}
|
||||||
|
|
||||||
class ForwardSingleMsg extends BaseAction<Payload, Response> {
|
abstract class ForwardSingleMsg extends BaseAction<Payload, Response> {
|
||||||
protected async getTargetPeer(payload: Payload): Promise<Peer> {
|
protected async getTargetPeer(payload: Payload): Promise<Peer> {
|
||||||
if (payload.user_id) {
|
if (payload.user_id) {
|
||||||
return { chatType: ChatType.friend, peerUid: getUidByUin(payload.user_id.toString()) }
|
return { chatType: ChatType.friend, peerUid: getUidByUin(payload.user_id.toString())! }
|
||||||
}
|
}
|
||||||
return { chatType: ChatType.group, peerUid: payload.group_id.toString() }
|
return { chatType: ChatType.group, peerUid: payload.group_id.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<Response> {
|
protected async _handle(payload: Payload): Promise<Response> {
|
||||||
const msg = await dbUtil.getMsgByShortId(payload.message_id)
|
const msg = (await dbUtil.getMsgByShortId(payload.message_id))!
|
||||||
const peer = await this.getTargetPeer(payload)
|
const peer = await this.getTargetPeer(payload)
|
||||||
const sentMsg = await NTQQMsgApi.forwardMsg(
|
const sentMsg = await NTQQMsgApi.forwardMsg(
|
||||||
{
|
{
|
||||||
@@ -35,7 +36,7 @@ class ForwardSingleMsg extends BaseAction<Payload, Response> {
|
|||||||
[msg.msgId],
|
[msg.msgId],
|
||||||
)
|
)
|
||||||
const ob11MsgId = await dbUtil.addMsg(sentMsg)
|
const ob11MsgId = await dbUtil.addMsg(sentMsg)
|
||||||
return {message_id: ob11MsgId}
|
return { message_id: ob11MsgId! }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,10 +7,9 @@ import {
|
|||||||
GroupMemberRole,
|
GroupMemberRole,
|
||||||
PicSubType,
|
PicSubType,
|
||||||
RawMessage,
|
RawMessage,
|
||||||
SendArkElement,
|
|
||||||
SendMessageElement,
|
SendMessageElement,
|
||||||
} from '../../../ntqqapi/types'
|
} from '../../../ntqqapi/types'
|
||||||
import { friends, getFriend, getGroup, getGroupMember, getUidByUin, selfInfo } from '../../../common/data'
|
import { friends, getGroup, getGroupMember, getUidByUin, selfInfo } from '../../../common/data'
|
||||||
import {
|
import {
|
||||||
OB11MessageCustomMusic,
|
OB11MessageCustomMusic,
|
||||||
OB11MessageData,
|
OB11MessageData,
|
||||||
@@ -20,68 +19,32 @@ import {
|
|||||||
OB11MessageMixType,
|
OB11MessageMixType,
|
||||||
OB11MessageMusic,
|
OB11MessageMusic,
|
||||||
OB11MessageNode,
|
OB11MessageNode,
|
||||||
OB11MessageVideo,
|
|
||||||
OB11PostSendMsg,
|
OB11PostSendMsg,
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { NTQQMsgApi, Peer } from '../../../ntqqapi/api/msg'
|
|
||||||
import { SendMsgElementConstructor } from '../../../ntqqapi/constructor'
|
import { SendMsgElementConstructor } from '../../../ntqqapi/constructor'
|
||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { ActionName, BaseCheckResult } from '../types'
|
import { ActionName, BaseCheckResult } from '../types'
|
||||||
import * as fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import { decodeCQCode } from '../../cqcode'
|
import { decodeCQCode } from '../../cqcode'
|
||||||
import { dbUtil } from '../../../common/db'
|
import { dbUtil } from '../../../common/db'
|
||||||
import { ALLOW_SEND_TEMP_MSG, getConfigUtil } from '../../../common/config'
|
import { ALLOW_SEND_TEMP_MSG, getConfigUtil } from '../../../common/config'
|
||||||
import { log } from '../../../common/utils/log'
|
import { log } from '../../../common/utils/log'
|
||||||
import { sleep } from '../../../common/utils/helper'
|
import { sleep } from '../../../common/utils/helper'
|
||||||
import { uri2local } from '../../../common/utils'
|
import { uri2local } from '../../../common/utils'
|
||||||
import { crychic } from '../../../ntqqapi/native/crychic'
|
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi, NTQQFriendApi } from '@/ntqqapi/api'
|
||||||
import { NTQQGroupApi } from '../../../ntqqapi/api'
|
import { CustomMusicSignPostData, IdMusicSignPostData, MusicSign, MusicSignPostData } from '@/common/utils/sign'
|
||||||
import { CustomMusicSignPostData, IdMusicSignPostData, MusicSign, MusicSignPostData } from '../../../common/utils/sign'
|
import { Peer } from '@/ntqqapi/types/msg'
|
||||||
|
|
||||||
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
|
||||||
function checkUri(uri: string): boolean {
|
|
||||||
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/
|
|
||||||
return pattern.test(uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let msg of sendMsgList) {
|
|
||||||
if (msg['type'] && msg['data']) {
|
|
||||||
let type = msg['type']
|
|
||||||
let data = msg['data']
|
|
||||||
if (type === 'text' && !data['text']) {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
else if (['image', 'voice', 'record'].includes(type)) {
|
|
||||||
if (!data['file']) {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (checkUri(data['file'])) {
|
|
||||||
return 200
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type === 'at' && !data['qq']) {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
else if (type === 'reply' && !data['id']) {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 200
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReturnDataType {
|
export interface ReturnDataType {
|
||||||
message_id: number
|
message_id: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ContextMode {
|
||||||
|
Normal = 0,
|
||||||
|
Private = 1,
|
||||||
|
Group = 2
|
||||||
|
}
|
||||||
|
|
||||||
export function convertMessage2List(message: OB11MessageMixType, autoEscape = false) {
|
export function convertMessage2List(message: OB11MessageMixType, autoEscape = false) {
|
||||||
if (typeof message === 'string') {
|
if (typeof message === 'string') {
|
||||||
if (autoEscape === true) {
|
if (autoEscape === true) {
|
||||||
@@ -106,7 +69,7 @@ export function convertMessage2List(message: OB11MessageMixType, autoEscape = fa
|
|||||||
|
|
||||||
export async function createSendElements(
|
export async function createSendElements(
|
||||||
messageData: OB11MessageData[],
|
messageData: OB11MessageData[],
|
||||||
target: Group | Friend | undefined,
|
peer: Peer,
|
||||||
ignoreTypes: OB11MessageDataType[] = [],
|
ignoreTypes: OB11MessageDataType[] = [],
|
||||||
) {
|
) {
|
||||||
let sendElements: SendMessageElement[] = []
|
let sendElements: SendMessageElement[] = []
|
||||||
@@ -124,7 +87,7 @@ export async function createSendElements(
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case OB11MessageDataType.at: {
|
case OB11MessageDataType.at: {
|
||||||
if (!target) {
|
if (!peer) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let atQQ = sendMsg.data?.qq
|
let atQQ = sendMsg.data?.qq
|
||||||
@@ -132,7 +95,7 @@ export async function createSendElements(
|
|||||||
atQQ = atQQ.toString()
|
atQQ = atQQ.toString()
|
||||||
if (atQQ === 'all') {
|
if (atQQ === 'all') {
|
||||||
// todo:查询剩余的at全体次数
|
// todo:查询剩余的at全体次数
|
||||||
const groupCode = (target as Group)?.groupCode
|
const groupCode = peer.peerUid
|
||||||
let remainAtAllCount = 1
|
let remainAtAllCount = 1
|
||||||
let isAdmin: boolean = true
|
let isAdmin: boolean = true
|
||||||
if (groupCode) {
|
if (groupCode) {
|
||||||
@@ -140,8 +103,8 @@ export async function createSendElements(
|
|||||||
remainAtAllCount = (await NTQQGroupApi.getGroupAtAllRemainCount(groupCode)).atInfo
|
remainAtAllCount = (await NTQQGroupApi.getGroupAtAllRemainCount(groupCode)).atInfo
|
||||||
.RemainAtAllCountForUin
|
.RemainAtAllCountForUin
|
||||||
log(`群${groupCode}剩余at全体次数`, remainAtAllCount)
|
log(`群${groupCode}剩余at全体次数`, remainAtAllCount)
|
||||||
const self = await getGroupMember((target as Group)?.groupCode, selfInfo.uin)
|
const self = await getGroupMember(groupCode, selfInfo.uin)
|
||||||
isAdmin = self.role === GroupMemberRole.admin || self.role === GroupMemberRole.owner
|
isAdmin = self?.role === GroupMemberRole.admin || self?.role === GroupMemberRole.owner
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,9 +112,9 @@ export async function createSendElements(
|
|||||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, '全体成员'))
|
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, '全体成员'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (peer.chatType === ChatType.group) {
|
||||||
// const atMember = group?.members.find(m => m.uin == atQQ)
|
// const atMember = group?.members.find(m => m.uin == atQQ)
|
||||||
const atMember = await getGroupMember((target as Group)?.groupCode, atQQ)
|
const atMember = await getGroupMember(peer.peerUid, atQQ)
|
||||||
if (atMember) {
|
if (atMember) {
|
||||||
sendElements.push(
|
sendElements.push(
|
||||||
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick),
|
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick),
|
||||||
@@ -170,8 +133,8 @@ export async function createSendElements(
|
|||||||
SendMsgElementConstructor.reply(
|
SendMsgElementConstructor.reply(
|
||||||
replyMsg.msgSeq,
|
replyMsg.msgSeq,
|
||||||
replyMsg.msgId,
|
replyMsg.msgId,
|
||||||
replyMsg.senderUin,
|
replyMsg.senderUin!,
|
||||||
replyMsg.senderUin,
|
replyMsg.senderUin!,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -250,7 +213,7 @@ export async function createSendElements(
|
|||||||
await SendMsgElementConstructor.pic(
|
await SendMsgElementConstructor.pic(
|
||||||
path,
|
path,
|
||||||
sendMsg.data.summary || '',
|
sendMsg.data.summary || '',
|
||||||
<PicSubType>parseInt(sendMsg.data?.subType?.toString()) || 0,
|
<PicSubType>parseInt(sendMsg.data?.subType?.toString()!) || 0,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -264,18 +227,6 @@ export async function createSendElements(
|
|||||||
break
|
break
|
||||||
case OB11MessageDataType.poke: {
|
case OB11MessageDataType.poke: {
|
||||||
let qq = sendMsg.data?.qq || sendMsg.data?.id
|
let qq = sendMsg.data?.qq || sendMsg.data?.id
|
||||||
if (qq) {
|
|
||||||
if ('groupCode' in target) {
|
|
||||||
crychic.sendGroupPoke(target.groupCode, qq.toString())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!qq) {
|
|
||||||
qq = parseInt(target.uin)
|
|
||||||
}
|
|
||||||
crychic.sendFriendPoke(qq.toString())
|
|
||||||
}
|
|
||||||
sendElements.push(SendMsgElementConstructor.poke('', ''))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case OB11MessageDataType.dice: {
|
case OB11MessageDataType.dice: {
|
||||||
@@ -337,6 +288,31 @@ export async function sendMsg(
|
|||||||
return returnMsg
|
return returnMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createContext(payload: OB11PostSendMsg, contextMode: ContextMode): Promise<Peer> {
|
||||||
|
// This function determines the type of message by the existence of user_id / group_id,
|
||||||
|
// not message_type.
|
||||||
|
// This redundant design of Ob11 here should be blamed.
|
||||||
|
|
||||||
|
if ((contextMode === ContextMode.Group || contextMode === ContextMode.Normal) && payload.group_id) {
|
||||||
|
const group = (await getGroup(payload.group_id))! // checked before
|
||||||
|
return {
|
||||||
|
chatType: ChatType.group,
|
||||||
|
peerUid: group.groupCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) {
|
||||||
|
const Uid = await NTQQUserApi.getUidByUin(payload.user_id.toString())
|
||||||
|
const isBuddy = await NTQQFriendApi.isBuddy(Uid!)
|
||||||
|
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy)
|
||||||
|
return {
|
||||||
|
chatType: isBuddy ? ChatType.friend : ChatType.temp,
|
||||||
|
peerUid: Uid!,
|
||||||
|
guildId: payload.group_id || ''//临时主动发起时需要传入群号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw '请指定 group_id 或 user_id'
|
||||||
|
}
|
||||||
|
|
||||||
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||||
actionName = ActionName.SendMsg
|
actionName = ActionName.SendMsg
|
||||||
|
|
||||||
@@ -363,13 +339,11 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (payload.user_id && payload.message_type !== 'group') {
|
if (payload.user_id && payload.message_type !== 'group') {
|
||||||
if (!(await getFriend(payload.user_id))) {
|
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString())
|
||||||
if (!ALLOW_SEND_TEMP_MSG && !(await dbUtil.getReceivedTempUinMap())[payload.user_id.toString()]) {
|
const isBuddy = await NTQQFriendApi.isBuddy(uid!)
|
||||||
return {
|
// 此处有问题
|
||||||
valid: false,
|
if (!isBuddy) {
|
||||||
message: `不能发送临时消息`,
|
//return { valid: false, message: '异常消息' }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -378,58 +352,16 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async _handle(payload: OB11PostSendMsg) {
|
protected async _handle(payload: OB11PostSendMsg) {
|
||||||
const peer: Peer = {
|
const peer = await createContext(payload, ContextMode.Normal)
|
||||||
chatType: ChatType.friend,
|
|
||||||
peerUid: '',
|
|
||||||
}
|
|
||||||
let isTempMsg = false
|
|
||||||
let group: Group | undefined = undefined
|
|
||||||
let friend: Friend | undefined = undefined
|
|
||||||
const genGroupPeer = async () => {
|
|
||||||
group = await getGroup(payload.group_id.toString())
|
|
||||||
peer.chatType = ChatType.group
|
|
||||||
// peer.name = group.name
|
|
||||||
peer.peerUid = group.groupCode
|
|
||||||
}
|
|
||||||
|
|
||||||
const genFriendPeer = () => {
|
|
||||||
friend = friends.find((f) => f.uin == payload.user_id.toString())
|
|
||||||
if (friend) {
|
|
||||||
// peer.name = friend.nickName
|
|
||||||
peer.peerUid = friend.uid
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
peer.chatType = ChatType.temp
|
|
||||||
const tempUserUid = getUidByUin(payload.user_id.toString())
|
|
||||||
if (!tempUserUid) {
|
|
||||||
throw `找不到私聊对象${payload.user_id}`
|
|
||||||
}
|
|
||||||
// peer.name = tempUser.nickName
|
|
||||||
isTempMsg = true
|
|
||||||
peer.peerUid = tempUserUid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (payload?.group_id && payload.message_type === 'group') {
|
|
||||||
await genGroupPeer()
|
|
||||||
}
|
|
||||||
else if (payload?.user_id) {
|
|
||||||
genFriendPeer()
|
|
||||||
}
|
|
||||||
else if (payload.group_id) {
|
|
||||||
await genGroupPeer()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw '发送消息参数错误, 请指定group_id或user_id'
|
|
||||||
}
|
|
||||||
const messages = convertMessage2List(
|
const messages = convertMessage2List(
|
||||||
payload.message,
|
payload.message,
|
||||||
payload.auto_escape === true || payload.auto_escape === 'true',
|
payload.auto_escape === true || payload.auto_escape === 'true',
|
||||||
)
|
)
|
||||||
if (this.getSpecialMsgNum(messages, OB11MessageDataType.node)) {
|
if (this.getSpecialMsgNum(messages, OB11MessageDataType.node)) {
|
||||||
try {
|
try {
|
||||||
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group)
|
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[])
|
||||||
return { message_id: returnMsg.msgShortId }
|
return { message_id: returnMsg?.msgShortId! }
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
throw '发送转发消息失败 ' + e.toString()
|
throw '发送转发消息失败 ' + e.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,8 +378,9 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
const postData: MusicSignPostData = { ...music.data }
|
const postData: MusicSignPostData = { ...music.data }
|
||||||
if (type === 'custom' && music.data.content) {
|
if (type === 'custom' && music.data.content) {
|
||||||
;(postData as CustomMusicSignPostData).singer = music.data.content
|
const data = postData as CustomMusicSignPostData
|
||||||
delete (postData as OB11MessageCustomMusic['data']).content
|
data.singer = music.data.content
|
||||||
|
delete (data as OB11MessageCustomMusic['data']).content
|
||||||
}
|
}
|
||||||
if (type === 'custom') {
|
if (type === 'custom') {
|
||||||
const customMusicData = music.data as CustomMusicSignPostData
|
const customMusicData = music.data as CustomMusicSignPostData
|
||||||
@@ -483,7 +416,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log("send msg:", peer, sendElements)
|
// log("send msg:", peer, sendElements)
|
||||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(messages, group || friend)
|
const { sendElements, deleteAfterSentFiles } = await createSendElements(messages, peer)
|
||||||
if (sendElements.length === 1) {
|
if (sendElements.length === 1) {
|
||||||
if (sendElements[0] === null) {
|
if (sendElements[0] === null) {
|
||||||
return { message_id: 0 }
|
return { message_id: 0 }
|
||||||
@@ -492,7 +425,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles)
|
const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles)
|
||||||
deleteAfterSentFiles.map((f) => fs.unlink(f, () => {
|
deleteAfterSentFiles.map((f) => fs.unlink(f, () => {
|
||||||
}))
|
}))
|
||||||
return { message_id: returnMsg.msgShortId }
|
return { message_id: returnMsg.msgShortId! }
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSpecialMsgNum(message: OB11MessageData[], msgType: OB11MessageDataType): number {
|
private getSpecialMsgNum(message: OB11MessageData[], msgType: OB11MessageDataType): number {
|
||||||
@@ -502,7 +435,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private async cloneMsg(msg: RawMessage): Promise<RawMessage> {
|
private async cloneMsg(msg: RawMessage): Promise<RawMessage | undefined> {
|
||||||
log('克隆的目标消息', msg)
|
log('克隆的目标消息', msg)
|
||||||
let sendElements: SendMessageElement[] = []
|
let sendElements: SendMessageElement[] = []
|
||||||
for (const ele of msg.elements) {
|
for (const ele of msg.elements) {
|
||||||
@@ -532,7 +465,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 返回一个合并转发的消息id
|
// 返回一个合并转发的消息id
|
||||||
private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[], group: Group | undefined) {
|
private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[]) {
|
||||||
const selfPeer = {
|
const selfPeer = {
|
||||||
chatType: ChatType.friend,
|
chatType: ChatType.friend,
|
||||||
peerUid: selfInfo.uid,
|
peerUid: selfInfo.uid,
|
||||||
@@ -548,11 +481,11 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
if (nodeId) {
|
if (nodeId) {
|
||||||
let nodeMsg = await dbUtil.getMsgByShortId(parseInt(nodeId))
|
let nodeMsg = await dbUtil.getMsgByShortId(parseInt(nodeId))
|
||||||
if (!needClone) {
|
if (!needClone) {
|
||||||
nodeMsgIds.push(nodeMsg.msgId)
|
nodeMsgIds.push(nodeMsg?.msgId!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nodeMsg.peerUid !== selfInfo.uid) {
|
if (nodeMsg?.peerUid !== selfInfo.uid) {
|
||||||
const cloneMsg = await this.cloneMsg(nodeMsg)
|
const cloneMsg = await this.cloneMsg(nodeMsg!)
|
||||||
if (cloneMsg) {
|
if (cloneMsg) {
|
||||||
nodeMsgIds.push(cloneMsg.msgId)
|
nodeMsgIds.push(cloneMsg.msgId)
|
||||||
}
|
}
|
||||||
@@ -565,7 +498,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
try {
|
try {
|
||||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(
|
const { sendElements, deleteAfterSentFiles } = await createSendElements(
|
||||||
convertMessage2List(messageNode.data.content),
|
convertMessage2List(messageNode.data.content),
|
||||||
group,
|
destPeer
|
||||||
)
|
)
|
||||||
log('开始生成转发节点', sendElements)
|
log('开始生成转发节点', sendElements)
|
||||||
let sendElementsSplit: SendMessageElement[][] = []
|
let sendElementsSplit: SendMessageElement[][] = []
|
||||||
@@ -604,7 +537,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
|
|
||||||
// 检查srcPeer是否一致,不一致则需要克隆成自己的消息, 让所有srcPeer都变成自己的,使其保持一致才能够转发
|
// 检查srcPeer是否一致,不一致则需要克隆成自己的消息, 让所有srcPeer都变成自己的,使其保持一致才能够转发
|
||||||
let nodeMsgArray: Array<RawMessage> = []
|
let nodeMsgArray: Array<RawMessage> = []
|
||||||
let srcPeer: Peer = null
|
let srcPeer: Peer | null = null
|
||||||
let needSendSelf = false
|
let needSendSelf = false
|
||||||
for (const [index, msgId] of nodeMsgIds.entries()) {
|
for (const [index, msgId] of nodeMsgIds.entries()) {
|
||||||
const nodeMsg = await dbUtil.getMsgByLongId(msgId)
|
const nodeMsg = await dbUtil.getMsgByLongId(msgId)
|
||||||
@@ -647,48 +580,12 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
log('开发转发', nodeMsgIds)
|
log('开发转发', nodeMsgIds)
|
||||||
return await NTQQMsgApi.multiForwardMsg(srcPeer, destPeer, nodeMsgIds)
|
return await NTQQMsgApi.multiForwardMsg(srcPeer!, destPeer, nodeMsgIds)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('forward failed', e)
|
log('forward failed', e)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement {
|
|
||||||
// const musicJson = {
|
|
||||||
// app: 'com.tencent.structmsg',
|
|
||||||
// config: {
|
|
||||||
// ctime: 1709689928,
|
|
||||||
// forward: 1,
|
|
||||||
// token: '5c1e4905f926dd3a64a4bd3841460351',
|
|
||||||
// type: 'normal',
|
|
||||||
// },
|
|
||||||
// extra: { app_type: 1, appid: 100497308, uin: selfInfo.uin },
|
|
||||||
// meta: {
|
|
||||||
// news: {
|
|
||||||
// action: '',
|
|
||||||
// android_pkg_name: '',
|
|
||||||
// app_type: 1,
|
|
||||||
// appid: 100497308,
|
|
||||||
// ctime: 1709689928,
|
|
||||||
// desc: content || title,
|
|
||||||
// jumpUrl: url,
|
|
||||||
// musicUrl: audio,
|
|
||||||
// preview: image,
|
|
||||||
// source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0',
|
|
||||||
// source_url: '',
|
|
||||||
// tag: 'QQ音乐',
|
|
||||||
// title: title,
|
|
||||||
// uin: selfInfo.uin,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// prompt: content || title,
|
|
||||||
// ver: '0.0.0.1',
|
|
||||||
// view: 'news',
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return SendMsgElementConstructor.ark(musicJson)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SendMsg
|
export default SendMsg
|
||||||
|
@@ -5,8 +5,8 @@ import { OB11Message, OB11MessageAt, OB11MessageData, OB11MessageDataType } from
|
|||||||
import { OB11FriendRequestEvent } from '../event/request/OB11FriendRequest'
|
import { OB11FriendRequestEvent } from '../event/request/OB11FriendRequest'
|
||||||
import { OB11GroupRequestEvent } from '../event/request/OB11GroupRequest'
|
import { OB11GroupRequestEvent } from '../event/request/OB11GroupRequest'
|
||||||
import { dbUtil } from '@/common/db'
|
import { dbUtil } from '@/common/db'
|
||||||
import { NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, Peer } from '@/ntqqapi/api'
|
import { NTQQFriendApi, NTQQGroupApi, NTQQMsgApi } from '@/ntqqapi/api'
|
||||||
import { ChatType, Group, GroupRequestOperateTypes } from '@/ntqqapi/types'
|
import { ChatType, Group, GroupRequestOperateTypes, Peer } from '@/ntqqapi/types'
|
||||||
import { getGroup, getUidByUin } from '@/common/data'
|
import { getGroup, getUidByUin } from '@/common/data'
|
||||||
import { convertMessage2List, createSendElements, sendMsg } from './msg/SendMsg'
|
import { convertMessage2List, createSendElements, sendMsg } from './msg/SendMsg'
|
||||||
import { isNull, log } from '@/common/utils'
|
import { isNull, log } from '@/common/utils'
|
||||||
@@ -71,17 +71,17 @@ async function handleMsg(msg: OB11Message, quickAction: QuickOperationPrivateMes
|
|||||||
peerUid: msg.user_id.toString(),
|
peerUid: msg.user_id.toString(),
|
||||||
}
|
}
|
||||||
if (msg.message_type == 'private') {
|
if (msg.message_type == 'private') {
|
||||||
peer.peerUid = getUidByUin(msg.user_id.toString())
|
peer.peerUid = getUidByUin(msg.user_id.toString())!
|
||||||
if (msg.sub_type === 'group') {
|
if (msg.sub_type === 'group') {
|
||||||
peer.chatType = ChatType.temp
|
peer.chatType = ChatType.temp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
peer.chatType = ChatType.group
|
peer.chatType = ChatType.group
|
||||||
peer.peerUid = msg.group_id.toString()
|
peer.peerUid = msg.group_id?.toString()!
|
||||||
}
|
}
|
||||||
if (reply) {
|
if (reply) {
|
||||||
let group: Group = null
|
let group: Group | null = null
|
||||||
let replyMessage: OB11MessageData[] = []
|
let replyMessage: OB11MessageData[] = []
|
||||||
if (ob11Config.enableQOAutoQuote) {
|
if (ob11Config.enableQOAutoQuote) {
|
||||||
replyMessage.push({
|
replyMessage.push({
|
||||||
@@ -93,7 +93,7 @@ async function handleMsg(msg: OB11Message, quickAction: QuickOperationPrivateMes
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msg.message_type == 'group') {
|
if (msg.message_type == 'group') {
|
||||||
group = await getGroup(msg.group_id.toString())
|
group = (await getGroup(msg.group_id?.toString()!))!
|
||||||
if ((quickAction as QuickOperationGroupMessage).at_sender) {
|
if ((quickAction as QuickOperationGroupMessage).at_sender) {
|
||||||
replyMessage.push({
|
replyMessage.push({
|
||||||
type: 'at',
|
type: 'at',
|
||||||
@@ -104,7 +104,7 @@ async function handleMsg(msg: OB11Message, quickAction: QuickOperationPrivateMes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
replyMessage = replyMessage.concat(convertMessage2List(reply, quickAction.auto_escape))
|
replyMessage = replyMessage.concat(convertMessage2List(reply, quickAction.auto_escape))
|
||||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(replyMessage, group)
|
const { sendElements, deleteAfterSentFiles } = await createSendElements(replyMessage, group!)
|
||||||
log(`发送消息给`, peer, sendElements)
|
log(`发送消息给`, peer, sendElements)
|
||||||
sendMsg(peer, sendElements, deleteAfterSentFiles, false).then().catch(log)
|
sendMsg(peer, sendElements, deleteAfterSentFiles, false).then().catch(log)
|
||||||
}
|
}
|
||||||
@@ -112,15 +112,15 @@ async function handleMsg(msg: OB11Message, quickAction: QuickOperationPrivateMes
|
|||||||
const groupMsgQuickAction = quickAction as QuickOperationGroupMessage
|
const groupMsgQuickAction = quickAction as QuickOperationGroupMessage
|
||||||
// handle group msg
|
// handle group msg
|
||||||
if (groupMsgQuickAction.delete) {
|
if (groupMsgQuickAction.delete) {
|
||||||
NTQQMsgApi.recallMsg(peer, [rawMessage.msgId]).then().catch(log)
|
NTQQMsgApi.recallMsg(peer, [rawMessage?.msgId!]).then().catch(log)
|
||||||
}
|
}
|
||||||
if (groupMsgQuickAction.kick) {
|
if (groupMsgQuickAction.kick) {
|
||||||
NTQQGroupApi.kickMember(peer.peerUid, [rawMessage.senderUid]).then().catch(log)
|
NTQQGroupApi.kickMember(peer.peerUid, [rawMessage?.senderUid!]).then().catch(log)
|
||||||
}
|
}
|
||||||
if (groupMsgQuickAction.ban) {
|
if (groupMsgQuickAction.ban) {
|
||||||
NTQQGroupApi.banMember(peer.peerUid, [
|
NTQQGroupApi.banMember(peer.peerUid, [
|
||||||
{
|
{
|
||||||
uid: rawMessage.senderUid,
|
uid: rawMessage?.senderUid!,
|
||||||
timeStamp: groupMsgQuickAction.ban_duration || 60 * 30,
|
timeStamp: groupMsgQuickAction.ban_duration || 60 * 30,
|
||||||
},
|
},
|
||||||
]).then().catch(log)
|
]).then().catch(log)
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import Path from 'path'
|
import Path from 'node:path'
|
||||||
import { ChatType, ChatCacheListItemBasic, CacheFileType } from '../../../ntqqapi/types'
|
import { ChatType, ChatCacheListItemBasic, CacheFileType } from '../../../ntqqapi/types'
|
||||||
import { dbUtil } from '../../../common/db'
|
|
||||||
import { NTQQFileApi, NTQQFileCacheApi } from '../../../ntqqapi/api/file'
|
import { NTQQFileApi, NTQQFileCacheApi } from '../../../ntqqapi/api/file'
|
||||||
|
|
||||||
export default class CleanCache extends BaseAction<void, void> {
|
export default class CleanCache extends BaseAction<void, void> {
|
||||||
@@ -12,14 +11,16 @@ export default class CleanCache extends BaseAction<void, void> {
|
|||||||
protected _handle(): Promise<void> {
|
protected _handle(): Promise<void> {
|
||||||
return new Promise<void>(async (res, rej) => {
|
return new Promise<void>(async (res, rej) => {
|
||||||
try {
|
try {
|
||||||
// dbUtil.clearCache();
|
// dbUtil.clearCache()
|
||||||
const cacheFilePaths: string[] = []
|
const cacheFilePaths: string[] = []
|
||||||
|
|
||||||
await NTQQFileCacheApi.setCacheSilentScan(false)
|
await NTQQFileCacheApi.setCacheSilentScan(false)
|
||||||
|
|
||||||
cacheFilePaths.push(await NTQQFileCacheApi.getHotUpdateCachePath())
|
cacheFilePaths.push(await NTQQFileCacheApi.getHotUpdateCachePath())
|
||||||
cacheFilePaths.push(await NTQQFileCacheApi.getDesktopTmpPath())
|
cacheFilePaths.push(await NTQQFileCacheApi.getDesktopTmpPath())
|
||||||
;(await NTQQFileCacheApi.getCacheSessionPathList()).forEach((e) => cacheFilePaths.push(e.value))
|
|
||||||
|
const list = await NTQQFileCacheApi.getCacheSessionPathList()
|
||||||
|
list.forEach((e) => cacheFilePaths.push(e.value))
|
||||||
|
|
||||||
// await NTQQApi.addCacheScannedPaths(); // XXX: 调用就崩溃,原因目前还未知
|
// await NTQQApi.addCacheScannedPaths(); // XXX: 调用就崩溃,原因目前还未知
|
||||||
const cacheScanResult = await NTQQFileCacheApi.scanCache()
|
const cacheScanResult = await NTQQFileCacheApi.scanCache()
|
||||||
|
@@ -8,7 +8,7 @@ export default class GetStatus extends BaseAction<any, OB11Status> {
|
|||||||
|
|
||||||
protected async _handle(payload: any): Promise<OB11Status> {
|
protected async _handle(payload: any): Promise<OB11Status> {
|
||||||
return {
|
return {
|
||||||
online: selfInfo.online,
|
online: selfInfo.online!,
|
||||||
good: true,
|
good: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ export enum ActionName {
|
|||||||
Debug = 'llonebot_debug',
|
Debug = 'llonebot_debug',
|
||||||
GetFile = 'get_file',
|
GetFile = 'get_file',
|
||||||
GetFriendsWithCategory = 'get_friends_with_category',
|
GetFriendsWithCategory = 'get_friends_with_category',
|
||||||
|
GetEvent = 'get_event',
|
||||||
// onebot 11
|
// onebot 11
|
||||||
SendLike = 'send_like',
|
SendLike = 'send_like',
|
||||||
GetLoginInfo = 'get_login_info',
|
GetLoginInfo = 'get_login_info',
|
||||||
@@ -70,4 +71,6 @@ export enum ActionName {
|
|||||||
GoCQHTTP_GetEssenceMsg = "get_essence_msg_list",
|
GoCQHTTP_GetEssenceMsg = "get_essence_msg_list",
|
||||||
GoCQHTTP_HandleQuickOperation = ".handle_quick_operation",
|
GoCQHTTP_HandleQuickOperation = ".handle_quick_operation",
|
||||||
GetGroupHonorInfo = "get_group_honor_info",
|
GetGroupHonorInfo = "get_group_honor_info",
|
||||||
|
GoCQHTTP_SetEssenceMsg = 'set_essence_msg',
|
||||||
|
GoCQHTTP_DelEssenceMsg = 'delete_essence_msg',
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import BaseAction from '../BaseAction'
|
|||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { NTQQFriendApi } from '@/ntqqapi/api'
|
import { NTQQFriendApi } from '@/ntqqapi/api'
|
||||||
import { CategoryFriend } from '@/ntqqapi/types'
|
import { CategoryFriend } from '@/ntqqapi/types'
|
||||||
|
import { qqPkgInfo } from '@/common/utils/QQBasicInfo'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
no_cache: boolean | string
|
no_cache: boolean | string
|
||||||
@@ -14,6 +15,9 @@ export class GetFriendList extends BaseAction<Payload, OB11User[]> {
|
|||||||
actionName = ActionName.GetFriendList
|
actionName = ActionName.GetFriendList
|
||||||
|
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
if (+qqPkgInfo.buildVersion >= 26702) {
|
||||||
|
return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(payload?.no_cache === true || payload?.no_cache === 'true'))
|
||||||
|
}
|
||||||
if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') {
|
if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') {
|
||||||
const _friends = await NTQQFriendApi.getFriends(true)
|
const _friends = await NTQQFriendApi.getFriends(true)
|
||||||
// log('强制刷新好友列表,结果: ', _friends)
|
// log('强制刷新好友列表,结果: ', _friends)
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
import BaseAction from '../BaseAction'
|
import BaseAction from '../BaseAction'
|
||||||
import { getFriend, getUidByUin, uidMaps } from '../../../common/data'
|
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { NTQQFriendApi } from '../../../ntqqapi/api/friend'
|
import { NTQQUserApi } from '@/ntqqapi/api'
|
||||||
import { log } from '../../../common/utils/log'
|
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
user_id: number
|
user_id: number
|
||||||
@@ -13,19 +11,12 @@ export default class SendLike extends BaseAction<Payload, null> {
|
|||||||
actionName = ActionName.SendLike
|
actionName = ActionName.SendLike
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<null> {
|
protected async _handle(payload: Payload): Promise<null> {
|
||||||
log('点赞参数', payload)
|
|
||||||
try {
|
try {
|
||||||
const qq = payload.user_id.toString()
|
const qq = payload.user_id.toString()
|
||||||
const friend = await getFriend(qq)
|
const uid: string = await NTQQUserApi.getUidByUin(qq) || ''
|
||||||
let uid: string
|
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1)
|
||||||
if (!friend) {
|
|
||||||
uid = getUidByUin(qq)
|
|
||||||
} else {
|
|
||||||
uid = friend.uid
|
|
||||||
}
|
|
||||||
let result = await NTQQFriendApi.likeFriend(uid, parseInt(payload.times?.toString()) || 1)
|
|
||||||
if (result.result !== 0) {
|
if (result.result !== 0) {
|
||||||
throw result.errMsg
|
throw Error(result.errMsg)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw `点赞失败 ${e}`
|
throw `点赞失败 ${e}`
|
||||||
|
@@ -15,6 +15,7 @@ import {
|
|||||||
FaceIndex,
|
FaceIndex,
|
||||||
GrayTipElementSubType,
|
GrayTipElementSubType,
|
||||||
Group,
|
Group,
|
||||||
|
Peer,
|
||||||
GroupMember,
|
GroupMember,
|
||||||
PicType,
|
PicType,
|
||||||
RawMessage,
|
RawMessage,
|
||||||
@@ -23,8 +24,9 @@ import {
|
|||||||
TipGroupElementType,
|
TipGroupElementType,
|
||||||
User,
|
User,
|
||||||
VideoElement,
|
VideoElement,
|
||||||
|
FriendV2
|
||||||
} from '../ntqqapi/types'
|
} from '../ntqqapi/types'
|
||||||
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap } from '../common/data'
|
import { deleteGroup, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
||||||
import { EventType } from './event/OB11BaseEvent'
|
import { EventType } from './event/OB11BaseEvent'
|
||||||
import { encodeCQCode } from './cqcode'
|
import { encodeCQCode } from './cqcode'
|
||||||
import { dbUtil } from '../common/db'
|
import { dbUtil } from '../common/db'
|
||||||
@@ -32,23 +34,22 @@ import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'
|
|||||||
import { OB11GroupBanEvent } from './event/notice/OB11GroupBanEvent'
|
import { OB11GroupBanEvent } from './event/notice/OB11GroupBanEvent'
|
||||||
import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNoticeEvent'
|
import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNoticeEvent'
|
||||||
import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent'
|
import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent'
|
||||||
import { NTQQUserApi } from '../ntqqapi/api/user'
|
|
||||||
import { NTQQFileApi } from '../ntqqapi/api/file'
|
|
||||||
import { calcQQLevel } from '../common/utils/qqlevel'
|
import { calcQQLevel } from '../common/utils/qqlevel'
|
||||||
import { log } from '../common/utils/log'
|
import { log } from '../common/utils/log'
|
||||||
import { sleep } from '../common/utils/helper'
|
import { isNull, sleep } from '../common/utils/helper'
|
||||||
import { getConfigUtil } from '../common/config'
|
import { getConfigUtil } from '../common/config'
|
||||||
import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent'
|
import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent'
|
||||||
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent'
|
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent'
|
||||||
import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'
|
import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'
|
||||||
import { NTQQGroupApi } from '../ntqqapi/api'
|
import { NTQQGroupApi, NTQQUserApi, NTQQFileApi, NTQQMsgApi } from '../ntqqapi/api'
|
||||||
import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent'
|
import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent'
|
||||||
import { mFaceCache } from '../ntqqapi/constructor'
|
import { mFaceCache } from '../ntqqapi/constructor'
|
||||||
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
|
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
|
||||||
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
||||||
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
||||||
|
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
|
||||||
let lastRKeyUpdateTime = 0
|
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent'
|
||||||
|
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent'
|
||||||
|
|
||||||
export class OB11Constructor {
|
export class OB11Constructor {
|
||||||
static async message(msg: RawMessage): Promise<OB11Message> {
|
static async message(msg: RawMessage): Promise<OB11Message> {
|
||||||
@@ -61,14 +62,14 @@ export class OB11Constructor {
|
|||||||
const message_type = msg.chatType == ChatType.group ? 'group' : 'private'
|
const message_type = msg.chatType == ChatType.group ? 'group' : 'private'
|
||||||
const resMsg: OB11Message = {
|
const resMsg: OB11Message = {
|
||||||
self_id: parseInt(selfInfo.uin),
|
self_id: parseInt(selfInfo.uin),
|
||||||
user_id: parseInt(msg.senderUin),
|
user_id: parseInt(msg.senderUin!),
|
||||||
time: parseInt(msg.msgTime) || Date.now(),
|
time: parseInt(msg.msgTime) || Date.now(),
|
||||||
message_id: msg.msgShortId,
|
message_id: msg.msgShortId!,
|
||||||
real_id: msg.msgShortId,
|
real_id: msg.msgShortId!,
|
||||||
message_seq: msg.msgShortId,
|
message_seq: msg.msgShortId!,
|
||||||
message_type: msg.chatType == ChatType.group ? 'group' : 'private',
|
message_type: msg.chatType == ChatType.group ? 'group' : 'private',
|
||||||
sender: {
|
sender: {
|
||||||
user_id: parseInt(msg.senderUin),
|
user_id: parseInt(msg.senderUin!),
|
||||||
nickname: msg.sendNickName,
|
nickname: msg.sendNickName,
|
||||||
card: msg.sendMemberName || '',
|
card: msg.sendMemberName || '',
|
||||||
},
|
},
|
||||||
@@ -85,7 +86,7 @@ export class OB11Constructor {
|
|||||||
if (msg.chatType == ChatType.group) {
|
if (msg.chatType == ChatType.group) {
|
||||||
resMsg.sub_type = 'normal'
|
resMsg.sub_type = 'normal'
|
||||||
resMsg.group_id = parseInt(msg.peerUin)
|
resMsg.group_id = parseInt(msg.peerUin)
|
||||||
const member = await getGroupMember(msg.peerUin, msg.senderUin)
|
const member = await getGroupMember(msg.peerUin, msg.senderUin!)
|
||||||
if (member) {
|
if (member) {
|
||||||
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role)
|
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role)
|
||||||
resMsg.sender.nickname = member.nick
|
resMsg.sender.nickname = member.nick
|
||||||
@@ -93,10 +94,7 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
else if (msg.chatType == ChatType.friend) {
|
else if (msg.chatType == ChatType.friend) {
|
||||||
resMsg.sub_type = 'friend'
|
resMsg.sub_type = 'friend'
|
||||||
const friend = await getFriend(msg.senderUin)
|
resMsg.sender.nickname = (await NTQQUserApi.getUserDetailInfo(msg.senderUid)).nick
|
||||||
if (friend) {
|
|
||||||
resMsg.sender.nickname = friend.nick
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (msg.chatType == ChatType.temp) {
|
else if (msg.chatType == ChatType.temp) {
|
||||||
resMsg.sub_type = 'group'
|
resMsg.sub_type = 'group'
|
||||||
@@ -107,33 +105,40 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let element of msg.elements) {
|
for (let element of msg.elements) {
|
||||||
let message_data: OB11MessageData | any = {
|
let message_data: OB11MessageData = {
|
||||||
data: {},
|
data: {} as any,
|
||||||
type: 'unknown',
|
type: 'unknown' as any,
|
||||||
}
|
}
|
||||||
if (element.textElement && element.textElement?.atType !== AtType.notAt) {
|
if (element.textElement && element.textElement?.atType !== AtType.notAt) {
|
||||||
message_data['type'] = OB11MessageDataType.at
|
let qq: string
|
||||||
|
let name: string | undefined
|
||||||
if (element.textElement.atType == AtType.atAll) {
|
if (element.textElement.atType == AtType.atAll) {
|
||||||
// message_data["data"]["mention"] = "all"
|
qq = 'all'
|
||||||
message_data['data']['qq'] = 'all'
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let atUid = element.textElement.atNtUid
|
const { atNtUid, content } = element.textElement
|
||||||
let atQQ = element.textElement.atUid
|
let atQQ = element.textElement.atUid
|
||||||
if (!atQQ || atQQ === '0') {
|
if (!atQQ || atQQ === '0') {
|
||||||
const atMember = await getGroupMember(msg.peerUin, atUid)
|
const atMember = await getGroupMember(msg.peerUin, atNtUid)
|
||||||
if (atMember) {
|
if (atMember) {
|
||||||
atQQ = atMember.uin
|
atQQ = atMember.uin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (atQQ) {
|
if (atQQ) {
|
||||||
// message_data["data"]["mention"] = atQQ
|
qq = atQQ
|
||||||
message_data['data']['qq'] = atQQ
|
name = content.replace('@', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message_data = {
|
||||||
|
type: OB11MessageDataType.at,
|
||||||
|
data: {
|
||||||
|
qq: qq!,
|
||||||
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (element.textElement) {
|
else if (element.textElement) {
|
||||||
message_data['type'] = 'text'
|
message_data['type'] = OB11MessageDataType.text
|
||||||
let text = element.textElement.content
|
let text = element.textElement.content
|
||||||
if (!text.trim()) {
|
if (!text.trim()) {
|
||||||
continue
|
continue
|
||||||
@@ -141,30 +146,32 @@ export class OB11Constructor {
|
|||||||
message_data['data']['text'] = text
|
message_data['data']['text'] = text
|
||||||
}
|
}
|
||||||
else if (element.replyElement) {
|
else if (element.replyElement) {
|
||||||
message_data['type'] = 'reply'
|
message_data['type'] = OB11MessageDataType.reply
|
||||||
// log("收到回复消息", element.replyElement.replayMsgSeq)
|
// log("收到回复消息", element.replyElement.replayMsgSeq)
|
||||||
try {
|
try {
|
||||||
const replyMsg = await dbUtil.getMsgBySeqId(element.replyElement.replayMsgSeq)
|
const replyMsg = await dbUtil.getMsgBySeqId(element.replyElement.replayMsgSeq)
|
||||||
// log("找到回复消息", replyMsg.msgShortId, replyMsg.msgId)
|
// log("找到回复消息", replyMsg.msgShortId, replyMsg.msgId)
|
||||||
if (replyMsg) {
|
if (replyMsg) {
|
||||||
message_data['data']['id'] = replyMsg.msgShortId.toString()
|
message_data['data']['id'] = replyMsg.msgShortId?.toString()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq)
|
log('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (element.picElement) {
|
else if (element.picElement) {
|
||||||
message_data['type'] = 'image'
|
message_data['type'] = OB11MessageDataType.image
|
||||||
// message_data["data"]["file"] = element.picElement.sourcePath
|
// message_data["data"]["file"] = element.picElement.sourcePath
|
||||||
let fileName = element.picElement.fileName
|
let fileName = element.picElement.fileName
|
||||||
const sourcePath = element.picElement.sourcePath
|
const sourcePath = element.picElement.sourcePath
|
||||||
if (element.picElement.picType === PicType.gif && !fileName.endsWith('.gif')) {
|
const isGif = element.picElement.picType === PicType.gif
|
||||||
|
if (isGif && !fileName.endsWith('.gif')) {
|
||||||
fileName += '.gif'
|
fileName += '.gif'
|
||||||
}
|
}
|
||||||
message_data['data']['file'] = fileName
|
message_data['data']['file'] = fileName
|
||||||
|
message_data['data']['subType'] = element.picElement.picSubType
|
||||||
// message_data["data"]["path"] = element.picElement.sourcePath
|
// message_data["data"]["path"] = element.picElement.sourcePath
|
||||||
// let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64"
|
// let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64"
|
||||||
|
|
||||||
@@ -188,9 +195,7 @@ export class OB11Constructor {
|
|||||||
element.picElement.sourcePath,
|
element.picElement.sourcePath,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
}).then()
|
||||||
.then()
|
|
||||||
// 不在自动下载图片
|
|
||||||
}
|
}
|
||||||
else if (element.videoElement || element.fileElement) {
|
else if (element.videoElement || element.fileElement) {
|
||||||
const videoOrFileElement = element.videoElement || element.fileElement
|
const videoOrFileElement = element.videoElement || element.fileElement
|
||||||
@@ -200,13 +205,20 @@ export class OB11Constructor {
|
|||||||
message_data['data']['path'] = videoOrFileElement.filePath
|
message_data['data']['path'] = videoOrFileElement.filePath
|
||||||
message_data['data']['file_id'] = videoOrFileElement.fileUuid
|
message_data['data']['file_id'] = videoOrFileElement.fileUuid
|
||||||
message_data['data']['file_size'] = videoOrFileElement.fileSize
|
message_data['data']['file_size'] = videoOrFileElement.fileSize
|
||||||
|
if (element.videoElement) {
|
||||||
|
message_data['data']['url'] = await NTQQFileApi.getVideoUrl({
|
||||||
|
chatType: msg.chatType,
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
}, msg.msgId, element.elementId,
|
||||||
|
)
|
||||||
|
}
|
||||||
dbUtil
|
dbUtil
|
||||||
.addFileCache(videoOrFileElement.fileUuid, {
|
.addFileCache(videoOrFileElement.fileUuid!, {
|
||||||
msgId: msg.msgId,
|
msgId: msg.msgId,
|
||||||
elementId: element.elementId,
|
elementId: element.elementId,
|
||||||
fileName: videoOrFileElement.fileName,
|
fileName: videoOrFileElement.fileName,
|
||||||
filePath: videoOrFileElement.filePath,
|
filePath: videoOrFileElement.filePath,
|
||||||
fileSize: videoOrFileElement.fileSize,
|
fileSize: videoOrFileElement.fileSize!,
|
||||||
downloadFunc: async () => {
|
downloadFunc: async () => {
|
||||||
await NTQQFileApi.downloadMedia(
|
await NTQQFileApi.downloadMedia(
|
||||||
msg.msgId,
|
msg.msgId,
|
||||||
@@ -214,7 +226,7 @@ export class OB11Constructor {
|
|||||||
msg.peerUid,
|
msg.peerUid,
|
||||||
element.elementId,
|
element.elementId,
|
||||||
ob11MessageDataType == OB11MessageDataType.video
|
ob11MessageDataType == OB11MessageDataType.video
|
||||||
? (videoOrFileElement as VideoElement).thumbPath.get(0)
|
? (videoOrFileElement as VideoElement).thumbPath?.get(0)
|
||||||
: null,
|
: null,
|
||||||
videoOrFileElement.filePath,
|
videoOrFileElement.filePath,
|
||||||
)
|
)
|
||||||
@@ -240,9 +252,9 @@ export class OB11Constructor {
|
|||||||
|
|
||||||
// log("收到语音消息", msg)
|
// log("收到语音消息", msg)
|
||||||
// window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => {
|
// window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => {
|
||||||
// console.log("语音转文字结果", text);
|
// console.log("语音转文字结果", text)
|
||||||
// }).catch(err => {
|
// }).catch(err => {
|
||||||
// console.log("语音转文字失败", err);
|
// console.log("语音转文字失败", err)
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
else if (element.arkElement) {
|
else if (element.arkElement) {
|
||||||
@@ -277,7 +289,7 @@ export class OB11Constructor {
|
|||||||
message_data['data']['emoji_id'] = element.marketFaceElement.emojiId
|
message_data['data']['emoji_id'] = element.marketFaceElement.emojiId
|
||||||
message_data['data']['emoji_package_id'] = String(element.marketFaceElement.emojiPackageId)
|
message_data['data']['emoji_package_id'] = String(element.marketFaceElement.emojiPackageId)
|
||||||
message_data['data']['key'] = element.marketFaceElement.key
|
message_data['data']['key'] = element.marketFaceElement.key
|
||||||
mFaceCache.set(md5, element.marketFaceElement.faceName)
|
mFaceCache.set(md5, element.marketFaceElement.faceName!)
|
||||||
}
|
}
|
||||||
else if (element.markdownElement) {
|
else if (element.markdownElement) {
|
||||||
message_data['type'] = OB11MessageDataType.markdown
|
message_data['type'] = OB11MessageDataType.markdown
|
||||||
@@ -287,10 +299,10 @@ export class OB11Constructor {
|
|||||||
message_data['type'] = OB11MessageDataType.forward
|
message_data['type'] = OB11MessageDataType.forward
|
||||||
message_data['data']['id'] = msg.msgId
|
message_data['data']['id'] = msg.msgId
|
||||||
}
|
}
|
||||||
if (message_data.type !== 'unknown' && message_data.data) {
|
if ((message_data.type as string) !== 'unknown' && message_data.data) {
|
||||||
const cqCode = encodeCQCode(message_data)
|
const cqCode = encodeCQCode(message_data)
|
||||||
if (messagePostFormat === 'string') {
|
if (messagePostFormat === 'string') {
|
||||||
;(resMsg.message as string) += cqCode
|
(resMsg.message as string) += cqCode
|
||||||
}
|
}
|
||||||
else (resMsg.message as OB11MessageData[]).push(message_data)
|
else (resMsg.message as OB11MessageData[]).push(message_data)
|
||||||
|
|
||||||
@@ -301,7 +313,36 @@ export class OB11Constructor {
|
|||||||
return resMsg
|
return resMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
static async GroupEvent(msg: RawMessage): Promise<OB11GroupNoticeEvent> {
|
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent | void> {
|
||||||
|
if (msg.chatType !== ChatType.friend) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const element of msg.elements) {
|
||||||
|
if (element.grayTipElement) {
|
||||||
|
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
|
||||||
|
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr)
|
||||||
|
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
|
//判断业务类型
|
||||||
|
//Poke事件
|
||||||
|
const pokedetail: any[] = json.items
|
||||||
|
//筛选item带有uid的元素
|
||||||
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
|
if (poke_uid.length == 2) {
|
||||||
|
return new OB11FriendPokeEvent(parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 好友增加事件
|
||||||
|
if (msg.msgType === 5 && msg.subMsgType === 12) {
|
||||||
|
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin))
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async GroupEvent(msg: RawMessage): Promise<OB11GroupNoticeEvent | void> {
|
||||||
if (msg.chatType !== ChatType.group) {
|
if (msg.chatType !== ChatType.group) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -311,14 +352,14 @@ export class OB11Constructor {
|
|||||||
const event = new OB11GroupCardEvent(
|
const event = new OB11GroupCardEvent(
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
parseInt(msg.senderUin),
|
parseInt(msg.senderUin),
|
||||||
msg.sendMemberName,
|
msg.sendMemberName!,
|
||||||
member.cardName,
|
member.cardName,
|
||||||
)
|
)
|
||||||
member.cardName = msg.sendMemberName
|
member.cardName = msg.sendMemberName!
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log("group msg", msg);
|
// log("group msg", msg)
|
||||||
for (let element of msg.elements) {
|
for (let element of msg.elements) {
|
||||||
const grayTipElement = element.grayTipElement
|
const grayTipElement = element.grayTipElement
|
||||||
const groupElement = grayTipElement?.groupElement
|
const groupElement = grayTipElement?.groupElement
|
||||||
@@ -344,10 +385,10 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
else if (groupElement.type === TipGroupElementType.ban) {
|
else if (groupElement.type === TipGroupElementType.ban) {
|
||||||
log('收到群群员禁言提示', groupElement)
|
log('收到群群员禁言提示', groupElement)
|
||||||
const memberUid = groupElement.shutUp.member.uid
|
const memberUid = groupElement.shutUp?.member.uid
|
||||||
const adminUid = groupElement.shutUp.admin.uid
|
const adminUid = groupElement.shutUp?.admin.uid
|
||||||
let memberUin: string = ''
|
let memberUin: string = ''
|
||||||
let duration = parseInt(groupElement.shutUp.duration)
|
let duration = parseInt(groupElement.shutUp?.duration!)
|
||||||
let sub_type: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban'
|
let sub_type: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban'
|
||||||
if (memberUid) {
|
if (memberUid) {
|
||||||
memberUin =
|
memberUin =
|
||||||
@@ -361,7 +402,7 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const adminUin =
|
const adminUin =
|
||||||
(await getGroupMember(msg.peerUid, adminUid))?.uin || (await NTQQUserApi.getUserDetailInfo(adminUid))?.uin
|
(await getGroupMember(msg.peerUid, adminUid!))?.uin || (await NTQQUserApi.getUserDetailInfo(adminUid!))?.uin
|
||||||
if (memberUin && adminUin) {
|
if (memberUin && adminUin) {
|
||||||
return new OB11GroupBanEvent(
|
return new OB11GroupBanEvent(
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
@@ -394,8 +435,8 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (element.fileElement) {
|
else if (element.fileElement) {
|
||||||
return new OB11GroupUploadNoticeEvent(parseInt(msg.peerUid), parseInt(msg.senderUin), {
|
return new OB11GroupUploadNoticeEvent(parseInt(msg.peerUid), parseInt(msg.senderUin!), {
|
||||||
id: element.fileElement.fileUuid,
|
id: element.fileElement.fileUuid!,
|
||||||
name: element.fileElement.fileName,
|
name: element.fileElement.fileName,
|
||||||
size: parseInt(element.fileElement.fileSize),
|
size: parseInt(element.fileElement.fileSize),
|
||||||
busid: element.fileElement.fileBizId || 0,
|
busid: element.fileElement.fileBizId || 0,
|
||||||
@@ -427,13 +468,13 @@ export class OB11Constructor {
|
|||||||
if (!msg) {
|
if (!msg) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return new OB11GroupMsgEmojiLikeEvent(parseInt(msg.peerUid), parseInt(senderUin), msg.msgShortId, [
|
return new OB11GroupMsgEmojiLikeEvent(parseInt(msg.peerUid), parseInt(senderUin), msg.msgShortId!, [
|
||||||
{
|
{
|
||||||
emoji_id: emojiId,
|
emoji_id: emojiId,
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log('解析表情回应消息失败', e.stack)
|
log('解析表情回应消息失败', e.stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,8 +487,8 @@ export class OB11Constructor {
|
|||||||
if (xmlElement?.content) {
|
if (xmlElement?.content) {
|
||||||
const regex = /jp="(\d+)"/g
|
const regex = /jp="(\d+)"/g
|
||||||
|
|
||||||
let matches = []
|
const matches: string[] = []
|
||||||
let match = null
|
let match: RegExpExecArray | null = null
|
||||||
|
|
||||||
while ((match = regex.exec(xmlElement.content)) !== null) {
|
while ((match = regex.exec(xmlElement.content)) !== null) {
|
||||||
matches.push(match[1])
|
matches.push(match[1])
|
||||||
@@ -485,27 +526,51 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
* */
|
* */
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
|
//判断业务类型
|
||||||
|
//Poke事件
|
||||||
|
const pokedetail: any[] = json.items
|
||||||
|
//筛选item带有uid的元素
|
||||||
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
|
if (poke_uid.length == 2) {
|
||||||
|
return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
||||||
|
log('收到群精华消息', json)
|
||||||
|
const searchParams = new URL(json.items[0].jp).searchParams
|
||||||
|
const msgSeq = searchParams.get('msgSeq')!
|
||||||
|
const Group = searchParams.get('groupCode')
|
||||||
|
const Businessid = searchParams.get('businessid')
|
||||||
|
const Peer: Peer = {
|
||||||
|
guildId: '',
|
||||||
|
chatType: ChatType.group,
|
||||||
|
peerUid: Group!
|
||||||
|
}
|
||||||
|
let msgList = (await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true)).msgList
|
||||||
|
const origMsg = await dbUtil.getMsgByLongId(msgList[0].msgId)
|
||||||
|
const postMsg = await dbUtil.getMsgBySeqId(origMsg?.msgSeq!) ?? origMsg
|
||||||
|
// 如果 senderUin 为 0,可能是 历史消息 或 自身消息
|
||||||
|
if (msgList[0].senderUin === '0') {
|
||||||
|
msgList[0].senderUin = postMsg?.senderUin ?? selfInfo.uin
|
||||||
|
}
|
||||||
|
return new OB11GroupEssenceEvent(parseInt(msg.peerUid), postMsg?.msgShortId!, parseInt(msgList[0].senderUin))
|
||||||
|
// 获取MsgSeq+Peer可获取具体消息
|
||||||
|
}
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
||||||
const memberUin = json.items[1].param[0]
|
const memberUin = json.items[1].param[0]
|
||||||
const title = json.items[3].txt
|
const title = json.items[3].txt
|
||||||
log('收到群成员新头衔消息', json)
|
log('收到群成员新头衔消息', json)
|
||||||
getGroupMember(msg.peerUid, memberUin).then((member) => {
|
getGroupMember(msg.peerUid, memberUin).then(member => {
|
||||||
|
if (!isNull(member)) {
|
||||||
member.memberSpecialTitle = title
|
member.memberSpecialTitle = title
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title)
|
return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async FriendAddEvent(msg: RawMessage): Promise<OB11FriendAddNoticeEvent | undefined> {
|
|
||||||
if (msg.chatType !== ChatType.friend) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (msg.msgType === 5 && msg.subMsgType === 12) {
|
|
||||||
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin))
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async RecallEvent(
|
static async RecallEvent(
|
||||||
@@ -521,16 +586,16 @@ export class OB11Constructor {
|
|||||||
const revokeElement = msgElement.grayTipElement.revokeElement
|
const revokeElement = msgElement.grayTipElement.revokeElement
|
||||||
if (isGroup) {
|
if (isGroup) {
|
||||||
const operator = await getGroupMember(msg.peerUid, revokeElement.operatorUid)
|
const operator = await getGroupMember(msg.peerUid, revokeElement.operatorUid)
|
||||||
const sender = await getGroupMember(msg.peerUid, revokeElement.origMsgSenderUid)
|
const sender = await getGroupMember(msg.peerUid, revokeElement.origMsgSenderUid!)
|
||||||
return new OB11GroupRecallNoticeEvent(
|
return new OB11GroupRecallNoticeEvent(
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
parseInt(sender.uin),
|
parseInt(sender?.uin!),
|
||||||
parseInt(operator.uin),
|
parseInt(operator?.uin!),
|
||||||
msg.msgShortId,
|
msg.msgShortId!,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new OB11FriendRecallNoticeEvent(parseInt(msg.senderUin), msg.msgShortId)
|
return new OB11FriendRecallNoticeEvent(parseInt(msg.senderUin!), msg.msgShortId!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +604,7 @@ export class OB11Constructor {
|
|||||||
user_id: parseInt(friend.uin),
|
user_id: parseInt(friend.uin),
|
||||||
nickname: friend.nick,
|
nickname: friend.nick,
|
||||||
remark: friend.remark,
|
remark: friend.remark,
|
||||||
sex: OB11Constructor.sex(friend.sex),
|
sex: OB11Constructor.sex(friend.sex!),
|
||||||
level: (friend.qqLevel && calcQQLevel(friend.qqLevel)) || 0,
|
level: (friend.qqLevel && calcQQLevel(friend.qqLevel)) || 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -555,6 +620,25 @@ export class OB11Constructor {
|
|||||||
return friends.map(OB11Constructor.friend)
|
return friends.map(OB11Constructor.friend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static friendsV2(friends: FriendV2[]): OB11User[] {
|
||||||
|
const data: OB11User[] = []
|
||||||
|
for (const friend of friends) {
|
||||||
|
const sexValue = this.sex(friend.baseInfo.sex!)
|
||||||
|
data.push({
|
||||||
|
...friend.baseInfo,
|
||||||
|
...friend.coreInfo,
|
||||||
|
user_id: parseInt(friend.coreInfo.uin),
|
||||||
|
nickname: friend.coreInfo.nick,
|
||||||
|
remark: friend.coreInfo.nick,
|
||||||
|
sex: sexValue,
|
||||||
|
level: 0,
|
||||||
|
categroyName: friend.categroyName,
|
||||||
|
categoryId: friend.categoryId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
static groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
static groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
||||||
return {
|
return {
|
||||||
4: OB11GroupMemberRole.owner,
|
4: OB11GroupMemberRole.owner,
|
||||||
@@ -578,7 +662,7 @@ export class OB11Constructor {
|
|||||||
user_id: parseInt(member.uin),
|
user_id: parseInt(member.uin),
|
||||||
nickname: member.nick,
|
nickname: member.nick,
|
||||||
card: member.cardName,
|
card: member.cardName,
|
||||||
sex: OB11Constructor.sex(member.sex),
|
sex: OB11Constructor.sex(member.sex!),
|
||||||
age: 0,
|
age: 0,
|
||||||
area: '',
|
area: '',
|
||||||
level: 0,
|
level: 0,
|
||||||
@@ -600,7 +684,7 @@ export class OB11Constructor {
|
|||||||
...user,
|
...user,
|
||||||
user_id: parseInt(user.uin),
|
user_id: parseInt(user.uin),
|
||||||
nickname: user.nick,
|
nickname: user.nick,
|
||||||
sex: OB11Constructor.sex(user.sex),
|
sex: OB11Constructor.sex(user.sex!),
|
||||||
age: 0,
|
age: 0,
|
||||||
qid: user.qid,
|
qid: user.qid,
|
||||||
login_days: 0,
|
login_days: 0,
|
||||||
|
@@ -60,7 +60,15 @@ export function encodeCQCode(data: OB11MessageData) {
|
|||||||
let result = '[CQ:' + data.type
|
let result = '[CQ:' + data.type
|
||||||
for (const name in data.data) {
|
for (const name in data.data) {
|
||||||
const value = data.data[name]
|
const value = data.data[name]
|
||||||
result += `,${name}=${CQCodeEscape(value)}`
|
if (value === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const text = value.toString()
|
||||||
|
result += `,${name}=${CQCodeEscape(text)}`
|
||||||
|
} catch (error) {
|
||||||
|
// If it can't be converted, skip this name-value pair
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result += ']'
|
result += ']'
|
||||||
return result
|
return result
|
||||||
|
@@ -11,5 +11,5 @@ export enum EventType {
|
|||||||
export abstract class OB11BaseEvent {
|
export abstract class OB11BaseEvent {
|
||||||
time = Math.floor(Date.now() / 1000)
|
time = Math.floor(Date.now() / 1000)
|
||||||
self_id = parseInt(selfInfo.uin)
|
self_id = parseInt(selfInfo.uin)
|
||||||
post_type: EventType
|
abstract post_type: EventType
|
||||||
}
|
}
|
||||||
|
@@ -2,5 +2,5 @@ import { EventType, OB11BaseEvent } from '../OB11BaseEvent'
|
|||||||
|
|
||||||
export abstract class OB11BaseMetaEvent extends OB11BaseEvent {
|
export abstract class OB11BaseMetaEvent extends OB11BaseEvent {
|
||||||
post_type = EventType.META
|
post_type = EventType.META
|
||||||
meta_event_type: string
|
abstract meta_event_type: string
|
||||||
}
|
}
|
||||||
|
@@ -2,5 +2,14 @@ import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'
|
|||||||
|
|
||||||
export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent {
|
||||||
notice_type = 'group_admin'
|
notice_type = 'group_admin'
|
||||||
sub_type: 'set' | 'unset' // "set" | "unset"
|
sub_type: 'set' | 'unset'
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
|
constructor(subType: 'set' | 'unset', groupId: number, userId: number) {
|
||||||
|
super()
|
||||||
|
this.sub_type = subType
|
||||||
|
this.group_id = groupId
|
||||||
|
this.user_id = userId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,8 @@ export class OB11GroupBanEvent extends OB11GroupNoticeEvent {
|
|||||||
operator_id: number
|
operator_id: number
|
||||||
duration: number
|
duration: number
|
||||||
sub_type: 'ban' | 'lift_ban'
|
sub_type: 'ban' | 'lift_ban'
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, operatorId: number, duration: number, sub_type: 'ban' | 'lift_ban') {
|
constructor(groupId: number, userId: number, operatorId: number, duration: number, sub_type: 'ban' | 'lift_ban') {
|
||||||
super()
|
super()
|
||||||
|
@@ -4,6 +4,8 @@ export class OB11GroupCardEvent extends OB11GroupNoticeEvent {
|
|||||||
notice_type = 'group_card'
|
notice_type = 'group_card'
|
||||||
card_new: string
|
card_new: string
|
||||||
card_old: string
|
card_old: string
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, cardNew: string, cardOld: string) {
|
constructor(groupId: number, userId: number, cardNew: string, cardOld: string) {
|
||||||
super()
|
super()
|
||||||
|
@@ -6,6 +6,8 @@ export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent {
|
|||||||
notice_type = 'group_decrease'
|
notice_type = 'group_decrease'
|
||||||
sub_type: GroupDecreaseSubType = 'leave' // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
sub_type: GroupDecreaseSubType = 'leave' // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
||||||
operator_id: number
|
operator_id: number
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
|
constructor(groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
|
||||||
super()
|
super()
|
||||||
|
16
src/onebot11/event/notice/OB11GroupEssenceEvent.ts
Normal file
16
src/onebot11/event/notice/OB11GroupEssenceEvent.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
|
||||||
|
export class OB11GroupEssenceEvent extends OB11GroupNoticeEvent {
|
||||||
|
notice_type = 'essence'
|
||||||
|
message_id: number
|
||||||
|
sender_id: number
|
||||||
|
sub_type: 'add' | 'delete' = 'add'
|
||||||
|
group_id: number
|
||||||
|
user_id: number = 0
|
||||||
|
|
||||||
|
constructor(groupId: number, message_id: number, sender_id: number) {
|
||||||
|
super()
|
||||||
|
this.group_id = groupId
|
||||||
|
this.message_id = message_id
|
||||||
|
this.sender_id = sender_id
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,14 @@
|
|||||||
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'
|
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'
|
||||||
|
|
||||||
type GroupIncreaseSubType = 'approve' | 'invite'
|
type GroupIncreaseSubType = 'approve' | 'invite'
|
||||||
|
|
||||||
export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent {
|
||||||
notice_type = 'group_increase'
|
notice_type = 'group_increase'
|
||||||
operator_id: number
|
operator_id: number
|
||||||
sub_type: GroupIncreaseSubType
|
sub_type: GroupIncreaseSubType
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, operatorId: number, subType: GroupIncreaseSubType = 'approve') {
|
constructor(groupId: number, userId: number, operatorId: number, subType: GroupIncreaseSubType = 'approve') {
|
||||||
super()
|
super()
|
||||||
this.group_id = groupId
|
this.group_id = groupId
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'
|
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'
|
||||||
|
|
||||||
export abstract class OB11GroupNoticeEvent extends OB11BaseNoticeEvent {
|
export abstract class OB11GroupNoticeEvent extends OB11BaseNoticeEvent {
|
||||||
group_id: number
|
abstract group_id: number
|
||||||
user_id: number
|
abstract user_id: number
|
||||||
|
abstract notice_type: string
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,8 @@ export class OB11GroupRecallNoticeEvent extends OB11GroupNoticeEvent {
|
|||||||
notice_type = 'group_recall'
|
notice_type = 'group_recall'
|
||||||
operator_id: number
|
operator_id: number
|
||||||
message_id: number
|
message_id: number
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, operatorId: number, messageId: number) {
|
constructor(groupId: number, userId: number, operatorId: number, messageId: number) {
|
||||||
super()
|
super()
|
||||||
|
@@ -4,6 +4,8 @@ export class OB11GroupTitleEvent extends OB11GroupNoticeEvent {
|
|||||||
notice_type = 'notify'
|
notice_type = 'notify'
|
||||||
sub_type = 'title'
|
sub_type = 'title'
|
||||||
title: string
|
title: string
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, title: string) {
|
constructor(groupId: number, userId: number, title: string) {
|
||||||
super()
|
super()
|
||||||
|
@@ -10,6 +10,8 @@ export interface GroupUploadFile {
|
|||||||
export class OB11GroupUploadNoticeEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupUploadNoticeEvent extends OB11GroupNoticeEvent {
|
||||||
notice_type = 'group_upload'
|
notice_type = 'group_upload'
|
||||||
file: GroupUploadFile
|
file: GroupUploadFile
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, file: GroupUploadFile) {
|
constructor(groupId: number, userId: number, file: GroupUploadFile) {
|
||||||
super()
|
super()
|
||||||
|
@@ -8,14 +8,17 @@ export interface MsgEmojiLike {
|
|||||||
export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent {
|
||||||
notice_type = 'group_msg_emoji_like'
|
notice_type = 'group_msg_emoji_like'
|
||||||
message_id: number
|
message_id: number
|
||||||
sub_type: 'ban' | 'lift_ban'
|
sub_type?: 'ban' | 'lift_ban'
|
||||||
likes: MsgEmojiLike[]
|
likes: MsgEmojiLike[]
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[]) {
|
constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[], sub_type?: 'ban' | 'lift_ban') {
|
||||||
super()
|
super()
|
||||||
this.group_id = groupId
|
this.group_id = groupId
|
||||||
this.user_id = userId // 可为空,表示是对别人的消息操作,如果是对bot自己的消息则不为空
|
this.user_id = userId // 可为空,表示是对别人的消息操作,如果是对bot自己的消息则不为空
|
||||||
this.message_id = messageId
|
this.message_id = messageId
|
||||||
this.likes = likes
|
this.likes = likes
|
||||||
|
this.sub_type = sub_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,30 +1,32 @@
|
|||||||
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'
|
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'
|
||||||
import { selfInfo } from '../../../common/data'
|
|
||||||
import { OB11BaseEvent } from '../OB11BaseEvent'
|
|
||||||
|
|
||||||
class OB11PokeEvent extends OB11BaseNoticeEvent {
|
abstract class OB11PokeEvent extends OB11BaseNoticeEvent {
|
||||||
notice_type = 'notify'
|
notice_type = 'notify'
|
||||||
sub_type = 'poke'
|
sub_type = 'poke'
|
||||||
target_id = parseInt(selfInfo.uin)
|
target_id = 0
|
||||||
user_id: number
|
abstract user_id: number
|
||||||
|
raw_message: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OB11FriendPokeEvent extends OB11PokeEvent {
|
export class OB11FriendPokeEvent extends OB11PokeEvent {
|
||||||
sender_id: number
|
user_id: number
|
||||||
constructor(user_id: number) {
|
|
||||||
super()
|
constructor(user_id: number, target_id: number, raw_message: any) {
|
||||||
this.user_id = user_id
|
super();
|
||||||
this.sender_id = user_id
|
this.target_id = target_id;
|
||||||
|
this.user_id = user_id;
|
||||||
|
this.raw_message = raw_message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OB11GroupPokeEvent extends OB11PokeEvent {
|
export class OB11GroupPokeEvent extends OB11PokeEvent {
|
||||||
|
user_id: number
|
||||||
group_id: number
|
group_id: number
|
||||||
|
constructor(group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) {
|
||||||
constructor(group_id: number, user_id: number = 0) {
|
|
||||||
super()
|
super()
|
||||||
this.group_id = group_id
|
this.group_id = group_id
|
||||||
this.target_id = user_id
|
this.target_id = target_id
|
||||||
this.user_id = user_id
|
this.user_id = user_id
|
||||||
|
this.raw_message = raw_message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,15 @@ import { EventType } from '../OB11BaseEvent'
|
|||||||
export class OB11FriendRequestEvent extends OB11BaseNoticeEvent {
|
export class OB11FriendRequestEvent extends OB11BaseNoticeEvent {
|
||||||
post_type = EventType.REQUEST
|
post_type = EventType.REQUEST
|
||||||
user_id: number
|
user_id: number
|
||||||
request_type: 'friend' = 'friend'
|
request_type: 'friend'
|
||||||
comment: string
|
comment: string
|
||||||
flag: string
|
flag: string
|
||||||
|
|
||||||
|
constructor(userId: number, comment: string, flag: string, requestType: 'friend' = 'friend') {
|
||||||
|
super()
|
||||||
|
this.user_id = userId
|
||||||
|
this.comment = comment
|
||||||
|
this.flag = flag
|
||||||
|
this.request_type = requestType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,24 @@
|
|||||||
import { OB11GroupNoticeEvent } from '../notice/OB11GroupNoticeEvent'
|
import { OB11BaseNoticeEvent } from '../notice/OB11BaseNoticeEvent'
|
||||||
import { EventType } from '../OB11BaseEvent'
|
import { EventType } from '../OB11BaseEvent'
|
||||||
|
|
||||||
export class OB11GroupRequestEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupRequestEvent extends OB11BaseNoticeEvent {
|
||||||
post_type = EventType.REQUEST
|
post_type = EventType.REQUEST
|
||||||
request_type: 'group' = 'group'
|
request_type: 'group'
|
||||||
sub_type: 'add' | 'invite' = 'add'
|
sub_type: 'add' | 'invite'
|
||||||
invitor_id: number | undefined = undefined
|
invitor_id: number | undefined
|
||||||
comment: string
|
comment?: string
|
||||||
flag: string
|
flag: string
|
||||||
|
group_id: number
|
||||||
|
user_id: number
|
||||||
|
|
||||||
|
constructor(groupId: number, userId: number, flag: string, comment?: string, invitorId?: number, subType: 'add' | 'invite' = 'add', requestType: 'group' = 'group') {
|
||||||
|
super()
|
||||||
|
this.group_id = groupId
|
||||||
|
this.user_id = userId
|
||||||
|
this.comment = comment
|
||||||
|
this.flag = flag
|
||||||
|
this.request_type = requestType
|
||||||
|
this.sub_type = subType
|
||||||
|
this.invitor_id = invitorId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
65
src/onebot11/server/event-for-http.ts
Normal file
65
src/onebot11/server/event-for-http.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { PostEventType } from './post-ob11-event'
|
||||||
|
|
||||||
|
interface HttpEventType {
|
||||||
|
seq: number
|
||||||
|
event: PostEventType
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HttpUserType {
|
||||||
|
lastAccessTime: number
|
||||||
|
userSeq: number
|
||||||
|
}
|
||||||
|
|
||||||
|
let curentSeq: number = 0
|
||||||
|
const eventList: HttpEventType[] = []
|
||||||
|
const httpUser: Record<string, HttpUserType> = {}
|
||||||
|
|
||||||
|
export function postHttpEvent(event: PostEventType) {
|
||||||
|
curentSeq += 1
|
||||||
|
eventList.push({
|
||||||
|
seq: curentSeq,
|
||||||
|
event: event
|
||||||
|
});
|
||||||
|
while (eventList.length > 100) {
|
||||||
|
eventList.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getHttpEvent(userKey: string, timeout = 0) {
|
||||||
|
const toRetEvent: PostEventType[] = []
|
||||||
|
|
||||||
|
// 清除过时的user,5分钟没访问过的user将被删除
|
||||||
|
const now = Date.now();
|
||||||
|
for (let key in httpUser) {
|
||||||
|
let user = httpUser[key]
|
||||||
|
if (now - user.lastAccessTime > 1000 * 60 * 5) {
|
||||||
|
delete httpUser[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加新的user
|
||||||
|
if (!httpUser[userKey]) {
|
||||||
|
httpUser[userKey] = {
|
||||||
|
lastAccessTime: now,
|
||||||
|
userSeq: curentSeq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = httpUser[userKey]
|
||||||
|
// 等待数据到来,暂时先这么写吧......
|
||||||
|
while (curentSeq == user.userSeq && Date.now() - now < timeout) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 10))
|
||||||
|
}
|
||||||
|
// 取数据
|
||||||
|
for (let i = 0; i < eventList.length; i++) {
|
||||||
|
let evt = eventList[i]
|
||||||
|
if (evt.seq > user.userSeq) {
|
||||||
|
toRetEvent.push(evt.event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新user数据
|
||||||
|
user.lastAccessTime = Date.now()
|
||||||
|
user.userSeq = curentSeq
|
||||||
|
return toRetEvent
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user