mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
91 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
57112c21a2 | ||
![]() |
0e8ceeb6c9 | ||
![]() |
f52b8d1f04 | ||
![]() |
f374cc77ae | ||
![]() |
7c694e7fae | ||
![]() |
932ffc2673 | ||
![]() |
3de5438139 | ||
![]() |
c4b5f34271 | ||
![]() |
22d3ac33a2 | ||
![]() |
2e5dd6535a | ||
![]() |
eac58a2a50 | ||
![]() |
e939ec0e52 | ||
![]() |
5b17a14a2a | ||
![]() |
8fb8c888f5 | ||
![]() |
4a2884509e | ||
![]() |
e295235a89 | ||
![]() |
ef515a38d0 | ||
![]() |
02cff040e3 | ||
![]() |
bb0f65a52d | ||
![]() |
d51d6a5cc1 | ||
![]() |
eb99379a79 | ||
![]() |
388eb57d0d | ||
![]() |
0b8131392a | ||
![]() |
229efbd006 | ||
![]() |
a482fa3a8d | ||
![]() |
6cf047af39 | ||
![]() |
41748c0b3f | ||
![]() |
1ce8be3c7e | ||
![]() |
32778acf57 | ||
![]() |
a3c71473ae | ||
![]() |
aceece7e90 | ||
![]() |
52efb4f9ef | ||
![]() |
6b0d96fe8d | ||
![]() |
ad052821b0 | ||
![]() |
da7636e60c | ||
![]() |
ef01dd0d77 | ||
![]() |
03f7d4673f | ||
![]() |
94e9c87978 | ||
![]() |
501bbbe4df | ||
![]() |
c9122a3fee | ||
![]() |
8a289d014e | ||
![]() |
ddadd38151 | ||
![]() |
0b8d0e3cac | ||
![]() |
eeb27d38bc | ||
![]() |
491a79ec96 | ||
![]() |
f429db61af | ||
![]() |
2881099602 | ||
![]() |
672ae8decf | ||
![]() |
2abc7e541d | ||
![]() |
45b1f369ac | ||
![]() |
3b5d2c8f6f | ||
![]() |
5376e16c9f | ||
![]() |
af052242fa | ||
![]() |
85e0b71545 | ||
![]() |
1206d1fcf6 | ||
![]() |
f7534dc438 | ||
![]() |
97f317254e | ||
![]() |
9eaf51e15f | ||
![]() |
7221f4ac02 | ||
![]() |
1bb6dce239 | ||
![]() |
d13db5e8eb | ||
![]() |
040b5535f3 | ||
![]() |
b44e1618fb | ||
![]() |
1e13483bc3 | ||
![]() |
f9519d3923 | ||
![]() |
86cdfbb79b | ||
![]() |
a70585e854 | ||
![]() |
040d0a8635 | ||
![]() |
efa512ab21 | ||
![]() |
9b04aed8b3 | ||
![]() |
7087eafe37 | ||
![]() |
c81c4af653 | ||
![]() |
c05cc9dd02 | ||
![]() |
1a0da00f2d | ||
![]() |
31b0c1d3d7 | ||
![]() |
53c1d40bcf | ||
![]() |
97cacb4383 | ||
![]() |
e03905abaf | ||
![]() |
06eba28b4c | ||
![]() |
bbfeac46dd | ||
![]() |
2fe4da094a | ||
![]() |
b454d8c0f9 | ||
![]() |
1f9b5453cc | ||
![]() |
3261791e99 | ||
![]() |
3bb12e3f45 | ||
![]() |
1dc2f7e5a2 | ||
![]() |
2531b08538 | ||
![]() |
9fcfb5493c | ||
![]() |
4576354c51 | ||
![]() |
1dcf2ef0c6 | ||
![]() |
3642c65e8c |
2
.env.universal
Normal file
2
.env.universal
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_BUILD_TYPE = Production
|
||||||
|
VITE_BUILD_PLATFORM = Universal
|
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -10,13 +10,12 @@ body:
|
|||||||
在提交新的 Bug 反馈前,请确保您:
|
在提交新的 Bug 反馈前,请确保您:
|
||||||
* 已经搜索了现有的 issues,并且没有找到可以解决您问题的方法
|
* 已经搜索了现有的 issues,并且没有找到可以解决您问题的方法
|
||||||
* 不与现有的某一 issue 重复
|
* 不与现有的某一 issue 重复
|
||||||
* 不涉及[已经停止维护的特性](https://github.com/NapNeko/NapCatQQ?tab=readme-ov-file#挥别昨日),例如 CQ 码
|
|
||||||
- type: input
|
- type: input
|
||||||
id: system-version
|
id: system-version
|
||||||
attributes:
|
attributes:
|
||||||
label: 系统版本
|
label: 系统版本
|
||||||
description: 运行 QQNT 的系统版本
|
description: 运行 QQNT 的系统版本
|
||||||
placeholder: Windows 10 Pro Workstation 22H2
|
placeholder: Windows 11 24H2
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
@@ -24,7 +23,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: QQNT 版本
|
label: QQNT 版本
|
||||||
description: 可在 QQNT 的「关于」的设置页中找到
|
description: 可在 QQNT 的「关于」的设置页中找到
|
||||||
placeholder: 9.9.7-21804
|
placeholder: 9.9.16-29927
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
@@ -40,21 +39,21 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: OneBot 客户端
|
label: OneBot 客户端
|
||||||
description: 连接至 NapCat 的客户端版本信息
|
description: 连接至 NapCat 的客户端版本信息
|
||||||
placeholder: Overflow 2.16.0-2cf7991-SNAPSHOT
|
placeholder: Karin 1.0.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: what-happened
|
id: what-happened
|
||||||
attributes:
|
attributes:
|
||||||
label: 发生了什么?
|
label: 发生了什么?
|
||||||
description: 填写你认为的 NapCat 的不正常行为
|
description: 填写你认为的 NapCat 的异常行为
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: how-reproduce
|
id: how-reproduce
|
||||||
attributes:
|
attributes:
|
||||||
label: 如何复现
|
label: 如何复现
|
||||||
description: 填写应当如何操作才能触发这个不正常行为
|
description: 填写应当如何操作才能触发这个异常行为
|
||||||
placeholder: |
|
placeholder: |
|
||||||
1. xxx
|
1. xxx
|
||||||
2. xxx
|
2. xxx
|
||||||
|
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -1,11 +1,6 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "npm" # See documentation for possible values
|
- package-ecosystem: "npm"
|
||||||
directory: "/" # Location of package manifests
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "weekly"
|
||||||
|
@@ -34,7 +34,14 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
|||||||
|
|
||||||
|
|
||||||
## 回家旅途
|
## 回家旅途
|
||||||
[QQ Group](https://qm.qq.com/q/NWP25OeV0c)
|
[QQ Group](https://qm.qq.com/q/I6LU87a0Yq)
|
||||||
|
|
||||||
|
## 性能设计/协议标准
|
||||||
|
NapCat 已实现90%+的OneBot/GoCQ标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
|
||||||
|
|
||||||
|
由此设计带来一系列好处,在开发中,获取群员列表通常小于50Ms,单条文本消息发送在320Ms以内,在1k+的群聊流程运行,同时带来一些副作用,上报数据中大量使用Magic生成字段, 消息Id无法持久,无法上报撤回消息原始内容。
|
||||||
|
|
||||||
|
NapCat在设计理念下遵守OneBot规范大多数要求并且积极改进,任何合理的标准化issue与pr将被接收。
|
||||||
|
|
||||||
## 感谢他们
|
## 感谢他们
|
||||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
||||||
|
BIN
external/LiteLoaderWrapper.zip
vendored
BIN
external/LiteLoaderWrapper.zip
vendored
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "qq-chat",
|
"name": "qq-chat",
|
||||||
"version": "9.9.16-29456",
|
"version": "9.9.16-29927",
|
||||||
"verHash": "dd395162",
|
"verHash": "3e273e30",
|
||||||
"linuxVersion": "3.2.13-29456",
|
"linuxVersion": "3.2.13-29927",
|
||||||
"linuxVerHash": "e379390a",
|
"linuxVerHash": "833d113c",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "QQ",
|
"description": "QQ",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"qd": "externals/devtools/cli/index.js"
|
"qd": "externals/devtools/cli/index.js"
|
||||||
},
|
},
|
||||||
"main": "./loadNapCat.js",
|
"main": "./loadNapCat.js",
|
||||||
"buildVersion": "29456",
|
"buildVersion": "29927",
|
||||||
"isPureShell": true,
|
"isPureShell": true,
|
||||||
"isByteCodeShell": true,
|
"isByteCodeShell": true,
|
||||||
"platform": "win32",
|
"platform": "win32",
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.2.1",
|
"version": "4.2.23",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,11 +2,13 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.2.1",
|
"version": "4.2.23",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||||
"build:shell": "npm run build:webui && vite build --mode shell || exit 1",
|
"build:shell": "npm run build:webui && vite build --mode shell || exit 1",
|
||||||
"build:webui": "cd napcat.webui && vite build",
|
"build:webui": "cd napcat.webui && vite build",
|
||||||
|
"dev:universal": "vite build --mode universal",
|
||||||
"dev:framework": "vite build --mode framework",
|
"dev:framework": "vite build --mode framework",
|
||||||
"dev:shell": "vite build --mode shell",
|
"dev:shell": "vite build --mode shell",
|
||||||
"dev:webui": "cd napcat.webui && npm run webui:dev",
|
"dev:webui": "cd napcat.webui && npm run webui:dev",
|
||||||
@@ -41,13 +43,13 @@
|
|||||||
"file-type": "^19.0.0",
|
"file-type": "^19.0.0",
|
||||||
"globals": "^15.12.0",
|
"globals": "^15.12.0",
|
||||||
"image-size": "^1.1.1",
|
"image-size": "^1.1.1",
|
||||||
"json-schema-to-ts": "^3.1.1",
|
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"typescript-eslint": "^8.13.0",
|
"typescript-eslint": "^8.13.0",
|
||||||
"vite": "^6.0.1",
|
"vite": "^6.0.1",
|
||||||
"vite-plugin-cp": "^4.0.8",
|
"vite-plugin-cp": "^4.0.8",
|
||||||
"vite-tsconfig-paths": "^5.1.0",
|
"vite-tsconfig-paths": "^5.1.0",
|
||||||
"winston": "^3.17.0"
|
"winston": "^3.17.0",
|
||||||
|
"@sinclair/typebox": "^0.34.9"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.0",
|
||||||
|
@@ -96,7 +96,7 @@ export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: Log
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.logError.bind(logger)('convert silk failed', error.stack);
|
logger.logError('convert silk failed', error.stack);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,27 +33,27 @@ export abstract class ConfigBase<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
read(copy_default: boolean = true): T {
|
read(copy_default: boolean = true): T {
|
||||||
const logger = this.core.context.logger;
|
|
||||||
const configPath = this.getConfigPath(this.core.selfInfo.uin);
|
const configPath = this.getConfigPath(this.core.selfInfo.uin);
|
||||||
if (!fs.existsSync(configPath) && copy_default) {
|
if (!fs.existsSync(configPath) && copy_default) {
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8'));
|
fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8'));
|
||||||
logger.log(`[Core] [Config] 配置文件创建成功!\n`);
|
this.core.context.logger.log(`[Core] [Config] 配置文件创建成功!\n`);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.logError.bind(logger)(`[Core] [Config] 创建配置文件时发生错误:`, e.message);
|
this.core.context.logger.logError(`[Core] [Config] 创建配置文件时发生错误:`, e.message);
|
||||||
}
|
}
|
||||||
} else if (!fs.existsSync(configPath) && !copy_default) {
|
} else if (!fs.existsSync(configPath) && !copy_default) {
|
||||||
fs.writeFileSync(configPath, '{}');
|
fs.writeFileSync(configPath, '{}');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
this.configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||||
logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
|
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
|
||||||
return this.configData;
|
return this.configData;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e instanceof SyntaxError) {
|
if (e instanceof SyntaxError) {
|
||||||
logger.logError.bind(logger)(`[Core] [Config] 配置文件格式错误,请检查配置文件:`, e.message);
|
this.core.context.logger.logError(`[Core] [Config] 配置文件格式错误,请检查配置文件:`, e.message);
|
||||||
} else {
|
} else {
|
||||||
logger.logError.bind(logger)(`[Core] [Config] 读取配置文件时发生错误:`, e.message);
|
this.core.context.logger.logError(`[Core] [Config] 读取配置文件时发生错误:`, e.message);
|
||||||
}
|
}
|
||||||
return {} as T;
|
return {} as T;
|
||||||
}
|
}
|
||||||
@@ -61,14 +61,13 @@ export abstract class ConfigBase<T> {
|
|||||||
|
|
||||||
|
|
||||||
save(newConfigData: T = this.configData) {
|
save(newConfigData: T = this.configData) {
|
||||||
const logger = this.core.context.logger;
|
|
||||||
const selfInfo = this.core.selfInfo;
|
const selfInfo = this.core.selfInfo;
|
||||||
this.configData = newConfigData;
|
this.configData = newConfigData;
|
||||||
const configPath = this.getConfigPath(selfInfo.uin);
|
const configPath = this.getConfigPath(selfInfo.uin);
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(configPath, JSON.stringify(newConfigData, this.getKeys(), 2));
|
fs.writeFileSync(configPath, JSON.stringify(newConfigData, this.getKeys(), 2));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.logError.bind(logger)(`保存配置文件 ${configPath} 时发生错误:`, e.message);
|
this.core.context.logger.logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { stat } from 'fs/promises';
|
import { stat } from 'fs/promises';
|
||||||
import crypto, { randomUUID } from 'crypto';
|
import crypto, { randomUUID } from 'crypto';
|
||||||
import util from 'util';
|
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import * as fileType from 'file-type';
|
|
||||||
import { solveProblem } from '@/common/helper';
|
import { solveProblem } from '@/common/helper';
|
||||||
|
|
||||||
export interface HttpDownloadOptions {
|
export interface HttpDownloadOptions {
|
||||||
@@ -15,7 +13,6 @@ type Uri2LocalRes = {
|
|||||||
success: boolean,
|
success: boolean,
|
||||||
errMsg: string,
|
errMsg: string,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
ext: string,
|
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,27 +70,6 @@ async function checkFile(path: string): Promise<void> {
|
|||||||
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function file2base64(path: string) {
|
|
||||||
const readFile = util.promisify(fs.readFile);
|
|
||||||
const result = {
|
|
||||||
err: '',
|
|
||||||
data: '',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
await checkFileExist(path, 5000);
|
|
||||||
} catch (e: any) {
|
|
||||||
result.err = e.toString();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const data = await readFile(path);
|
|
||||||
result.data = data.toString('base64');
|
|
||||||
} catch (err: any) {
|
|
||||||
result.err = err.toString();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 创建一个流式读取器
|
// 创建一个流式读取器
|
||||||
@@ -160,20 +136,6 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
|||||||
return Buffer.from(buffer);
|
return Buffer.from(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkFileV2(filePath: string) {
|
|
||||||
try {
|
|
||||||
const ext: string | undefined = (await fileType.fileTypeFromFile(filePath))?.ext;
|
|
||||||
if (ext) {
|
|
||||||
fs.renameSync(filePath, filePath + `.${ext}`);
|
|
||||||
filePath += `.${ext}`;
|
|
||||||
return { success: true, ext: ext, path: filePath };
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// log("获取文件类型失败", filePath,e.stack)
|
|
||||||
}
|
|
||||||
return { success: false, ext: '', path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum FileUriType {
|
export enum FileUriType {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Local = 1,
|
Local = 1,
|
||||||
@@ -190,16 +152,17 @@ export async function checkUriType(Uri: string) {
|
|||||||
}, Uri);
|
}, Uri);
|
||||||
if (LocalFileRet) return LocalFileRet;
|
if (LocalFileRet) return LocalFileRet;
|
||||||
const OtherFileRet = await solveProblem((uri: string) => {
|
const OtherFileRet = await solveProblem((uri: string) => {
|
||||||
//再判断是否是Http
|
// 再判断是否是Http
|
||||||
if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
if (uri.startsWith('http:') || uri.startsWith('https:')) {
|
||||||
return { Uri: uri, Type: FileUriType.Remote };
|
return { Uri: uri, Type: FileUriType.Remote };
|
||||||
}
|
}
|
||||||
//再判断是否是Base64
|
// 再判断是否是Base64
|
||||||
if (uri.startsWith('base64://')) {
|
if (uri.startsWith('base64:')) {
|
||||||
return { Uri: uri, Type: FileUriType.Base64 };
|
return { Uri: uri, Type: FileUriType.Base64 };
|
||||||
}
|
}
|
||||||
if (uri.startsWith('file://')) {
|
// 默认file://
|
||||||
let filePath: string = uri.slice(7);
|
if (uri.startsWith('file:')) {
|
||||||
|
const filePath: string = decodeURIComponent(uri.startsWith('file:///') && process.platform === 'win32' ? uri.slice(8) : uri.slice(7));
|
||||||
return { Uri: filePath, Type: FileUriType.Local };
|
return { Uri: filePath, Type: FileUriType.Local };
|
||||||
}
|
}
|
||||||
if (uri.startsWith('data:')) {
|
if (uri.startsWith('data:')) {
|
||||||
@@ -212,63 +175,32 @@ export async function checkUriType(Uri: string) {
|
|||||||
return { Uri: Uri, Type: FileUriType.Unknown };
|
return { Uri: Uri, Type: FileUriType.Unknown };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function uri2local(dir: string, uri: string, filename: string | undefined = undefined): Promise<Uri2LocalRes> {
|
export async function uriToLocalFile(dir: string, uri: string): Promise<Uri2LocalRes> {
|
||||||
const { Uri: HandledUri, Type: UriType } = await checkUriType(uri);
|
const { Uri: HandledUri, Type: UriType } = await checkUriType(uri);
|
||||||
|
|
||||||
//解析失败
|
const filename = randomUUID();
|
||||||
const tempName = randomUUID();
|
const filePath = path.join(dir, filename);
|
||||||
if (!filename) filename = randomUUID();
|
|
||||||
|
|
||||||
//解析Http和Https协议
|
switch (UriType) {
|
||||||
if (UriType == FileUriType.Unknown) {
|
case FileUriType.Local:
|
||||||
return { success: false, errMsg: `未知文件类型, uri= ${uri}`, fileName: '', ext: '', path: '' };
|
const fileExt = path.extname(HandledUri);
|
||||||
}
|
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
|
||||||
|
const tempFilePath = path.join(dir, filename + fileExt);
|
||||||
|
fs.copyFileSync(HandledUri, tempFilePath);
|
||||||
|
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
|
||||||
|
|
||||||
//解析File协议和本地文件
|
case FileUriType.Remote:
|
||||||
if (UriType == FileUriType.Local) {
|
const buffer = await httpDownload(HandledUri);
|
||||||
const fileExt = path.extname(HandledUri);
|
fs.writeFileSync(filePath, buffer, { flag: 'wx' });
|
||||||
let filename = path.basename(HandledUri, fileExt);
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
filename += fileExt;
|
|
||||||
//复制文件到临时文件并保持后缀
|
|
||||||
const filenameTemp = tempName + fileExt;
|
|
||||||
const filePath = path.join(dir, filenameTemp);
|
|
||||||
fs.copyFileSync(HandledUri, filePath);
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
//接下来都要有文件名
|
|
||||||
if (UriType == FileUriType.Remote) {
|
|
||||||
const pathInfo = path.parse(decodeURIComponent(new URL(HandledUri).pathname));
|
|
||||||
if (pathInfo.name) {
|
|
||||||
const pathlen = 200 - dir.length - pathInfo.name.length;
|
|
||||||
filename = pathlen > 0 ? pathInfo.name.substring(0, pathlen) : pathInfo.name.substring(pathInfo.name.length, pathInfo.name.length - 10);//过长截断
|
|
||||||
if (pathInfo.ext) {
|
|
||||||
filename += pathInfo.ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filename = filename.replace(/[/\\:*?"<>|]/g, '_');
|
|
||||||
const fileExt = path.extname(HandledUri).replace(/[/\\:*?"<>|]/g, '_').substring(0, 10);
|
|
||||||
const filePath = path.join(dir, tempName + fileExt);
|
|
||||||
const buffer = await httpDownload(HandledUri);
|
|
||||||
//没有文件就创建
|
|
||||||
fs.writeFileSync(filePath, buffer, { flag: 'wx' });
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
//解析Base64
|
case FileUriType.Base64:
|
||||||
if (UriType == FileUriType.Base64) {
|
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
||||||
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
const base64Buffer = Buffer.from(base64, 'base64');
|
||||||
const buffer = Buffer.from(base64, 'base64');
|
fs.writeFileSync(filePath, base64Buffer, { flag: 'wx' });
|
||||||
let filePath = path.join(dir, filename);
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
let fileExt = '';
|
|
||||||
fs.writeFileSync(filePath, buffer);
|
default:
|
||||||
const { success, ext, path: fileTypePath } = await checkFileV2(filePath);
|
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
|
||||||
if (success) {
|
|
||||||
filePath = fileTypePath;
|
|
||||||
fileExt = ext;
|
|
||||||
filename = filename + '.' + ext;
|
|
||||||
}
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
}
|
||||||
return { success: false, errMsg: `未知文件类型, uri= ${uri}`, fileName: '', ext: '', path: '' };
|
}
|
||||||
}
|
|
@@ -1,9 +1,9 @@
|
|||||||
import winston, { format, transports } from 'winston';
|
import winston, { format, transports } from 'winston';
|
||||||
import { truncateString } from '@/common/helper';
|
import { truncateString } from '@/common/helper';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs/promises';
|
||||||
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core';
|
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core';
|
||||||
|
import EventEmitter from 'node:events';
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
DEBUG = 'debug',
|
DEBUG = 'debug',
|
||||||
INFO = 'info',
|
INFO = 'info',
|
||||||
@@ -24,6 +24,36 @@ function getFormattedTimestamp() {
|
|||||||
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logEmitter = new EventEmitter();
|
||||||
|
export type LogListener = (msg: string) => void;
|
||||||
|
class Subscription {
|
||||||
|
public static MAX_HISTORY = 100;
|
||||||
|
public static history: string[] = [];
|
||||||
|
|
||||||
|
subscribe(listener: LogListener) {
|
||||||
|
for (const history of Subscription.history) {
|
||||||
|
try {
|
||||||
|
listener(history);
|
||||||
|
} catch (_) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logEmitter.on('log', listener);
|
||||||
|
}
|
||||||
|
unsubscribe(listener: LogListener) {
|
||||||
|
logEmitter.off('log', listener);
|
||||||
|
}
|
||||||
|
notify(msg: string) {
|
||||||
|
logEmitter.emit('log', msg);
|
||||||
|
if (Subscription.history.length >= Subscription.MAX_HISTORY) {
|
||||||
|
Subscription.history.shift();
|
||||||
|
}
|
||||||
|
Subscription.history.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logSubscription = new Subscription();
|
||||||
|
|
||||||
export class LogWrapper {
|
export class LogWrapper {
|
||||||
fileLogEnabled = true;
|
fileLogEnabled = true;
|
||||||
consoleLogEnabled = true;
|
consoleLogEnabled = true;
|
||||||
@@ -47,7 +77,7 @@ export class LogWrapper {
|
|||||||
filename: logPath,
|
filename: logPath,
|
||||||
level: 'debug',
|
level: 'debug',
|
||||||
maxsize: 5 * 1024 * 1024, // 5MB
|
maxsize: 5 * 1024 * 1024, // 5MB
|
||||||
maxFiles: 5
|
maxFiles: 5,
|
||||||
}),
|
}),
|
||||||
new transports.Console({
|
new transports.Console({
|
||||||
format: format.combine(
|
format: format.combine(
|
||||||
@@ -56,9 +86,9 @@ export class LogWrapper {
|
|||||||
const userInfo = meta.userInfo ? `${meta.userInfo} | ` : '';
|
const userInfo = meta.userInfo ? `${meta.userInfo} | ` : '';
|
||||||
return `${timestamp} [${level}] ${userInfo}${message}`;
|
return `${timestamp} [${level}] ${userInfo}${message}`;
|
||||||
})
|
})
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setLogSelfInfo({ nick: '', uid: '' });
|
this.setLogSelfInfo({ nick: '', uid: '' });
|
||||||
@@ -67,26 +97,20 @@ export class LogWrapper {
|
|||||||
|
|
||||||
cleanOldLogs(logDir: string) {
|
cleanOldLogs(logDir: string) {
|
||||||
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
||||||
fs.readdir(logDir, (err, files) => {
|
fs.readdir(logDir).then((files) => {
|
||||||
if (err) {
|
files.forEach((file) => {
|
||||||
this.logger.error('Failed to read log directory', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
files.forEach(file => {
|
|
||||||
const filePath = path.join(logDir, file);
|
const filePath = path.join(logDir, file);
|
||||||
this.deleteOldLogFile(filePath, oneWeekAgo);
|
this.deleteOldLogFile(filePath, oneWeekAgo);
|
||||||
});
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
this.logger.error('Failed to read log directory', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
||||||
fs.stat(filePath, (err, stats) => {
|
fs.stat(filePath).then((stats) => {
|
||||||
if (err) {
|
|
||||||
this.logger.error('Failed to get file stats', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (stats.mtime.getTime() < oneWeekAgo) {
|
if (stats.mtime.getTime() < oneWeekAgo) {
|
||||||
fs.unlink(filePath, err => {
|
fs.unlink(filePath).catch((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.code === 'ENOENT') {
|
if (err.code === 'ENOENT') {
|
||||||
this.logger.warn(`File already deleted: ${filePath}`);
|
this.logger.warn(`File already deleted: ${filePath}`);
|
||||||
@@ -98,6 +122,8 @@ export class LogWrapper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
this.logger.error('Failed to get file stats', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +137,7 @@ export class LogWrapper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setLogSelfInfo(selfInfo: { nick: string, uid: string }) {
|
setLogSelfInfo(selfInfo: { nick: string; uid: string }) {
|
||||||
const userInfo = `${selfInfo.nick}`;
|
const userInfo = `${selfInfo.nick}`;
|
||||||
this.logger.defaultMeta = { userInfo };
|
this.logger.defaultMeta = { userInfo };
|
||||||
}
|
}
|
||||||
@@ -135,14 +161,16 @@ export class LogWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatMsg(msg: any[]) {
|
formatMsg(msg: any[]) {
|
||||||
return msg.map(msgItem => {
|
return msg
|
||||||
if (msgItem instanceof Error) {
|
.map((msgItem) => {
|
||||||
return msgItem.stack;
|
if (msgItem instanceof Error) {
|
||||||
} else if (typeof msgItem === 'object') {
|
return msgItem.stack;
|
||||||
return JSON.stringify(truncateString(JSON.parse(JSON.stringify(msgItem, null, 2))));
|
} else if (typeof msgItem === 'object') {
|
||||||
}
|
return JSON.stringify(truncateString(JSON.parse(JSON.stringify(msgItem, null, 2))));
|
||||||
return msgItem;
|
}
|
||||||
}).join(' ');
|
return msgItem;
|
||||||
|
})
|
||||||
|
.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
_log(level: LogLevel, ...args: any[]) {
|
_log(level: LogLevel, ...args: any[]) {
|
||||||
@@ -155,6 +183,7 @@ export class LogWrapper {
|
|||||||
// eslint-disable-next-line no-control-regex
|
// eslint-disable-next-line no-control-regex
|
||||||
this.logger.log(level, message.replace(/\x1B[@-_][0-?]*[ -/]*[@-~]/g, ''));
|
this.logger.log(level, message.replace(/\x1B[@-_][0-?]*[ -/]*[@-~]/g, ''));
|
||||||
}
|
}
|
||||||
|
logSubscription.notify(JSON.stringify({ level, message }));
|
||||||
}
|
}
|
||||||
|
|
||||||
log(...args: any[]) {
|
log(...args: any[]) {
|
||||||
@@ -282,13 +311,9 @@ function textElementToText(textElement: any): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string {
|
function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string {
|
||||||
const recordMsgOrNull = msg.records.find(
|
const recordMsgOrNull = msg.records.find((record) => replyElement.sourceMsgIdInRecords === record.msgId);
|
||||||
record => replyElement.sourceMsgIdInRecords === record.msgId,
|
return `[回复消息 ${recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
||||||
);
|
? rawMessageToText(recordMsgOrNull, recursiveLevel + 1)
|
||||||
return `[回复消息 ${recordMsgOrNull &&
|
: `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
|
||||||
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
}]`;
|
||||||
?
|
}
|
||||||
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
|
|
||||||
`未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
|
|
||||||
}]`;
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
import { readFileSync } from 'node:fs';
|
|
||||||
|
|
||||||
export class RequestUtil {
|
export class RequestUtil {
|
||||||
// 适用于获取服务器下发cookies时获取,仅GET
|
// 适用于获取服务器下发cookies时获取,仅GET
|
||||||
@@ -69,7 +68,7 @@ export class RequestUtil {
|
|||||||
// 'Content-Length': Buffer.byteLength(postData),
|
// 'Content-Length': Buffer.byteLength(postData),
|
||||||
// },
|
// },
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const req = protocol.request(options, (res: any) => {
|
const req = protocol.request(options, (res: http.IncomingMessage) => {
|
||||||
let responseBody = '';
|
let responseBody = '';
|
||||||
res.on('data', (chunk: string | Buffer) => {
|
res.on('data', (chunk: string | Buffer) => {
|
||||||
responseBody += chunk.toString();
|
responseBody += chunk.toString();
|
||||||
@@ -112,24 +111,4 @@ export class RequestUtil {
|
|||||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
||||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async createFormData(boundary: string, filePath: string): Promise<Buffer> {
|
|
||||||
let type = 'image/png';
|
|
||||||
if (filePath.endsWith('.jpg')) {
|
|
||||||
type = 'image/jpeg';
|
|
||||||
}
|
|
||||||
const formDataParts = [
|
|
||||||
`------${boundary}\r\n`,
|
|
||||||
`Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`,
|
|
||||||
'Content-Type: ' + type + '\r\n\r\n',
|
|
||||||
];
|
|
||||||
|
|
||||||
const fileContent = readFileSync(filePath);
|
|
||||||
const footer = `\r\n------${boundary}--`;
|
|
||||||
return Buffer.concat([
|
|
||||||
Buffer.from(formDataParts.join(''), 'utf8'),
|
|
||||||
fileContent,
|
|
||||||
Buffer.from(footer, 'utf8'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.2.1';
|
export const napCatVersion = '4.2.23';
|
||||||
|
@@ -6,7 +6,6 @@ import {
|
|||||||
Peer,
|
Peer,
|
||||||
PicElement,
|
PicElement,
|
||||||
PicSubType,
|
PicSubType,
|
||||||
PicType,
|
|
||||||
RawMessage,
|
RawMessage,
|
||||||
SendFileElement,
|
SendFileElement,
|
||||||
SendPicElement,
|
SendPicElement,
|
||||||
@@ -17,7 +16,7 @@ import path from 'path';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import fsPromises from 'fs/promises';
|
import fsPromises from 'fs/promises';
|
||||||
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
||||||
import * as fileType from 'file-type';
|
import { fileTypeFromFile } from 'file-type';
|
||||||
import imageSize from 'image-size';
|
import imageSize from 'image-size';
|
||||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||||
import { RkeyManager } from '@/core/helper/rkey';
|
import { RkeyManager } from '@/core/helper/rkey';
|
||||||
@@ -62,7 +61,7 @@ export class NTQQFileApi {
|
|||||||
|
|
||||||
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
||||||
const fileMd5 = await calculateFileMD5(filePath);
|
const fileMd5 = await calculateFileMD5(filePath);
|
||||||
const extOrEmpty = (await fileType.fileTypeFromFile(filePath))?.ext;
|
let extOrEmpty = await fileTypeFromFile(filePath).then(e => e?.ext ?? '').catch(e => '');
|
||||||
const ext = extOrEmpty ? `.${extOrEmpty}` : '';
|
const ext = extOrEmpty ? `.${extOrEmpty}` : '';
|
||||||
let fileName = `${path.basename(filePath)}`;
|
let fileName = `${path.basename(filePath)}`;
|
||||||
if (fileName.indexOf('.') === -1) {
|
if (fileName.indexOf('.') === -1) {
|
||||||
@@ -142,7 +141,6 @@ export class NTQQFileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createValidSendVideoElement(context: SendMessageContext, filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise<SendVideoElement> {
|
async createValidSendVideoElement(context: SendMessageContext, filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise<SendVideoElement> {
|
||||||
const logger = this.core.context.logger;
|
|
||||||
let videoInfo = {
|
let videoInfo = {
|
||||||
width: 1920,
|
width: 1920,
|
||||||
height: 1080,
|
height: 1080,
|
||||||
@@ -152,17 +150,17 @@ export class NTQQFileApi {
|
|||||||
filePath,
|
filePath,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
videoInfo = await getVideoInfo(filePath, logger);
|
videoInfo = await getVideoInfo(filePath, this.context.logger);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.logError.bind(logger)('获取视频信息失败,将使用默认值', e);
|
this.context.logger.logError('获取视频信息失败,将使用默认值', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileExt = 'mp4';
|
let fileExt = 'mp4';
|
||||||
try {
|
try {
|
||||||
const tempExt = (await fileType.fileTypeFromFile(filePath))?.ext;
|
const tempExt = (await fileTypeFromFile(filePath))?.ext;
|
||||||
if (tempExt) fileExt = tempExt;
|
if (tempExt) fileExt = tempExt;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.logError.bind(logger)('获取文件类型失败', e);
|
this.context.logger.logError('获取文件类型失败', e);
|
||||||
}
|
}
|
||||||
const newFilePath = filePath + '.' + fileExt;
|
const newFilePath = filePath + '.' + fileExt;
|
||||||
fs.copyFileSync(filePath, newFilePath);
|
fs.copyFileSync(filePath, newFilePath);
|
||||||
@@ -183,7 +181,7 @@ export class NTQQFileApi {
|
|||||||
ffmpeg(filePath)
|
ffmpeg(filePath)
|
||||||
.on('error', (err) => {
|
.on('error', (err) => {
|
||||||
try {
|
try {
|
||||||
logger.logDebug('获取视频封面失败,使用默认封面', err);
|
this.context.logger.logDebug('获取视频封面失败,使用默认封面', err);
|
||||||
if (diyThumbPath) {
|
if (diyThumbPath) {
|
||||||
fsPromises.copyFile(diyThumbPath, thumbPath).then(() => {
|
fsPromises.copyFile(diyThumbPath, thumbPath).then(() => {
|
||||||
resolve(thumbPath);
|
resolve(thumbPath);
|
||||||
@@ -193,7 +191,7 @@ export class NTQQFileApi {
|
|||||||
resolve(thumbPath);
|
resolve(thumbPath);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.logError.bind(logger)('获取视频封面失败,使用默认封面失败', error);
|
this.context.logger.logError('获取视频封面失败,使用默认封面失败', error);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.screenshots({
|
.screenshots({
|
||||||
@@ -230,6 +228,7 @@ export class NTQQFileApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createValidSendPttElement(pttPath: string): Promise<SendPttElement> {
|
async createValidSendPttElement(pttPath: string): Promise<SendPttElement> {
|
||||||
|
|
||||||
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
||||||
if (!silkPath) {
|
if (!silkPath) {
|
||||||
throw new Error('语音转换失败, 请检查语音文件是否正常');
|
throw new Error('语音转换失败, 请检查语音文件是否正常');
|
||||||
@@ -239,8 +238,7 @@ export class NTQQFileApi {
|
|||||||
throw new Error('文件异常,大小为0');
|
throw new Error('文件异常,大小为0');
|
||||||
}
|
}
|
||||||
if (converted) {
|
if (converted) {
|
||||||
fsPromises.unlink(silkPath).then().catch(
|
fsPromises.unlink(silkPath).then().catch((e) => this.context.logger.logError('删除临时文件失败', e)
|
||||||
(e) => this.context.logger.logError.bind(this.context.logger)('删除临时文件失败', e)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -454,7 +452,7 @@ export class NTQQFileApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取rkey失败', error.message);
|
this.context.logger.logError('获取rkey失败', error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rkeyData.online_rkey) {
|
if (!rkeyData.online_rkey) {
|
||||||
@@ -464,7 +462,7 @@ export class NTQQFileApi {
|
|||||||
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
||||||
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取rkey失败 Fallback Old Mode', e);
|
this.context.logger.logError('获取rkey失败 Fallback Old Mode', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { FriendV2 } from '@/core/types';
|
import { FriendRequest, FriendV2 } from '@/core/types';
|
||||||
import { BuddyListReqType, InstanceContext, NapCatCore } from '@/core';
|
import { BuddyListReqType, InstanceContext, NapCatCore } from '@/core';
|
||||||
import { LimitedHashTable } from '@/common/message-unique';
|
import { LimitedHashTable } from '@/common/message-unique';
|
||||||
|
|
||||||
@@ -79,16 +79,10 @@ export class NTQQFriendApi {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleFriendRequest(flag: string, accept: boolean) {
|
async handleFriendRequest(notify: FriendRequest, accept: boolean) {
|
||||||
const data = flag.split('|');
|
|
||||||
if (data.length < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const friendUid = data[0];
|
|
||||||
const reqTime = data[1];
|
|
||||||
this.context.session.getBuddyService()?.approvalFriendRequest({
|
this.context.session.getBuddyService()?.approvalFriendRequest({
|
||||||
friendUid: friendUid,
|
friendUid: notify.friendUid,
|
||||||
reqTime: reqTime,
|
reqTime: notify.reqTime,
|
||||||
accept,
|
accept,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
GeneralCallResult,
|
GeneralCallResult,
|
||||||
Group,
|
|
||||||
GroupMember,
|
GroupMember,
|
||||||
NTGroupMemberRole,
|
NTGroupMemberRole,
|
||||||
NTGroupRequestOperateTypes,
|
NTGroupRequestOperateTypes,
|
||||||
@@ -8,6 +7,7 @@ import {
|
|||||||
KickMemberV2Req,
|
KickMemberV2Req,
|
||||||
MemberExtSourceType,
|
MemberExtSourceType,
|
||||||
NapCatCore,
|
NapCatCore,
|
||||||
|
GroupNotify,
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
||||||
import { LimitedHashTable } from '@/common/message-unique';
|
import { LimitedHashTable } from '@/common/message-unique';
|
||||||
@@ -16,34 +16,22 @@ import { NTEventWrapper } from '@/common/event';
|
|||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
core: NapCatCore;
|
core: NapCatCore;
|
||||||
groupCache: Map<string, Group> = new Map<string, Group>();
|
|
||||||
groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
|
groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
|
||||||
groups: Group[] = [];
|
|
||||||
essenceLRU = new LimitedHashTable<number, string>(1000);
|
essenceLRU = new LimitedHashTable<number, string>(1000);
|
||||||
session: any;
|
|
||||||
|
|
||||||
constructor(context: InstanceContext, core: NapCatCore) {
|
constructor(context: InstanceContext, core: NapCatCore) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
async initApi() {
|
async initApi() {
|
||||||
this.initCache().then().catch(this.context.logger.logError.bind(this.context.logger));
|
this.initCache().then().catch(e => this.context.logger.logError(e));
|
||||||
}
|
|
||||||
async initCache() {
|
|
||||||
this.groups = await this.getGroups();
|
|
||||||
for (const group of this.groups) {
|
|
||||||
this.groupCache.set(group.groupCode, group);
|
|
||||||
}
|
|
||||||
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
|
|
||||||
// process.pid 调试点
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCoreAndBaseInfo(uids: string[]) {
|
async initCache() {
|
||||||
return await this.core.eventWrapper.callNoListenerEvent(
|
for (const group of await this.getGroups(true)) {
|
||||||
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
this.refreshGroupMemberCache(group.groupCode).then().catch();
|
||||||
'nodeStore',
|
}
|
||||||
uids,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchGroupEssenceList(groupCode: string) {
|
async fetchGroupEssenceList(groupCode: string) {
|
||||||
@@ -54,20 +42,22 @@ export class NTQQGroupApi {
|
|||||||
pageLimit: 300,
|
pageLimit: 300,
|
||||||
}, pskey);
|
}, pskey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupShutUpMemberList(groupCode: string) {
|
async getGroupShutUpMemberList(groupCode: string) {
|
||||||
const data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', (group_id) => group_id === groupCode, 1, 1000);
|
const data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', (group_id) => group_id === groupCode, 1, 1000);
|
||||||
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
||||||
return (await data)[1];
|
return (await data)[1];
|
||||||
}
|
}
|
||||||
async clearGroupNotifiesUnreadCount(uk: boolean) {
|
|
||||||
return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(uk);
|
async clearGroupNotifiesUnreadCount(doubt: boolean) {
|
||||||
|
return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(doubt);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setGroupAvatar(gc: string, filePath: string) {
|
async setGroupAvatar(groupCode: string, filePath: string) {
|
||||||
return this.context.session.getGroupService().setHeader(gc, filePath);
|
return this.context.session.getGroupService().setHeader(groupCode, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroups(forced = false) {
|
async getGroups(forced: boolean = false) {
|
||||||
const [, , groupList] = await this.core.eventWrapper.callNormalEventV2(
|
const [, , groupList] = await this.core.eventWrapper.callNormalEventV2(
|
||||||
'NodeIKernelGroupService/getGroupList',
|
'NodeIKernelGroupService/getGroupList',
|
||||||
'NodeIKernelGroupListener/onGroupListUpdate',
|
'NodeIKernelGroupListener/onGroupListUpdate',
|
||||||
@@ -76,9 +66,9 @@ export class NTQQGroupApi {
|
|||||||
return groupList;
|
return groupList;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupExtFE0Info(groupCode: string[], forced = true) {
|
async getGroupExtFE0Info(groupCodes: Array<string>, forced = true) {
|
||||||
return this.context.session.getGroupService().getGroupExt0xEF0Info(
|
return this.context.session.getGroupService().getGroupExt0xEF0Info(
|
||||||
groupCode,
|
groupCodes,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
bindGuildId: 1,
|
bindGuildId: 1,
|
||||||
@@ -118,53 +108,42 @@ export class NTQQGroupApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroup(groupCode: string, forced = false) {
|
|
||||||
let group = this.groupCache.get(groupCode.toString());
|
|
||||||
if (!group) {
|
|
||||||
try {
|
|
||||||
const groupList = await this.getGroups(forced);
|
|
||||||
if (groupList.length) {
|
|
||||||
groupList.forEach(g => {
|
|
||||||
this.groupCache.set(g.groupCode, g);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
group = this.groupCache.get(groupCode.toString());
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getGroupMemberAll(groupCode: string, forced = false) {
|
async getGroupMemberAll(groupCode: string, forced = false) {
|
||||||
return this.context.session.getGroupService().getAllMemberList(groupCode, forced);
|
return this.context.session.getGroupService().getAllMemberList(groupCode, forced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refreshGroupMemberCache(groupCode: string) {
|
||||||
|
try {
|
||||||
|
const members = await this.getGroupMemberAll(groupCode, true);
|
||||||
|
this.groupMemberCache.set(groupCode, members.result.infos);
|
||||||
|
} catch (e) {
|
||||||
|
this.context.logger.logError(`刷新群成员缓存失败, 群号: ${groupCode}, 错误: ${e}`);
|
||||||
|
}
|
||||||
|
return this.groupMemberCache;
|
||||||
|
}
|
||||||
|
|
||||||
async getGroupMember(groupCode: string | number, memberUinOrUid: string | number) {
|
async getGroupMember(groupCode: string | number, memberUinOrUid: string | number) {
|
||||||
const groupCodeStr = groupCode.toString();
|
const groupCodeStr = groupCode.toString();
|
||||||
const memberUinOrUidStr = memberUinOrUid.toString();
|
const memberUinOrUidStr = memberUinOrUid.toString();
|
||||||
|
|
||||||
|
// 获取群成员缓存
|
||||||
let members = this.groupMemberCache.get(groupCodeStr);
|
let members = this.groupMemberCache.get(groupCodeStr);
|
||||||
if (!members) {
|
if (!members) {
|
||||||
try {
|
members = (await this.refreshGroupMemberCache(groupCodeStr)).get(groupCodeStr);
|
||||||
members = await this.getGroupMembers(groupCodeStr);
|
|
||||||
this.groupMemberCache.set(groupCodeStr, members);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getMember() {
|
|
||||||
let member: GroupMember | undefined;
|
|
||||||
if (isNumeric(memberUinOrUidStr)) {
|
|
||||||
member = Array.from(members!.values()).find(member => member.uin === memberUinOrUidStr);
|
|
||||||
} else {
|
|
||||||
member = members!.get(memberUinOrUidStr);
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getMember = () => {
|
||||||
|
if (isNumeric(memberUinOrUidStr)) {
|
||||||
|
return Array.from(members!.values()).find(member => member.uin === memberUinOrUidStr);
|
||||||
|
} else {
|
||||||
|
return members!.get(memberUinOrUidStr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let member = getMember();
|
let member = getMember();
|
||||||
|
// 如果缓存中不存在该成员,尝试刷新缓存
|
||||||
if (!member) {
|
if (!member) {
|
||||||
members = await this.getGroupMembers(groupCodeStr);
|
members = (await this.refreshGroupMemberCache(groupCodeStr)).get(groupCodeStr);
|
||||||
member = getMember();
|
member = getMember();
|
||||||
}
|
}
|
||||||
return member;
|
return member;
|
||||||
@@ -174,26 +153,26 @@ export class NTQQGroupApi {
|
|||||||
return this.context.session.getGroupService().getGroupRecommendContactArkJson(groupCode);
|
return this.context.session.getGroupService().getGroupRecommendContactArkJson(groupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async CreatGroupFileFolder(groupCode: string, folderName: string) {
|
async creatGroupFileFolder(groupCode: string, folderName: string) {
|
||||||
return this.context.session.getRichMediaService().createGroupFolder(groupCode, folderName);
|
return this.context.session.getRichMediaService().createGroupFolder(groupCode, folderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async DelGroupFile(groupCode: string, files: string[]) {
|
async delGroupFile(groupCode: string, files: Array<string>) {
|
||||||
return this.context.session.getRichMediaService().deleteGroupFile(groupCode, [102], files);
|
return this.context.session.getRichMediaService().deleteGroupFile(groupCode, [102], files);
|
||||||
}
|
}
|
||||||
|
|
||||||
async DelGroupFileFolder(groupCode: string, folderId: string) {
|
async delGroupFileFolder(groupCode: string, folderId: string) {
|
||||||
return this.context.session.getRichMediaService().deleteGroupFolder(groupCode, folderId);
|
return this.context.session.getRichMediaService().deleteGroupFolder(groupCode, folderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addGroupEssence(GroupCode: string, msgId: string) {
|
async addGroupEssence(groupCode: string, msgId: string) {
|
||||||
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
||||||
chatType: 2,
|
chatType: 2,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
peerUid: GroupCode,
|
peerUid: groupCode,
|
||||||
}, msgId, 1, false);
|
}, msgId, 1, false);
|
||||||
const param = {
|
const param = {
|
||||||
groupCode: GroupCode,
|
groupCode: groupCode,
|
||||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
||||||
};
|
};
|
||||||
@@ -204,9 +183,9 @@ export class NTQQGroupApi {
|
|||||||
return this.context.session.getGroupService().kickMemberV2(param);
|
return this.context.session.getGroupService().kickMemberV2(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteGroupBulletin(GroupCode: string, noticeId: string) {
|
async deleteGroupBulletin(groupCode: string, noticeId: string) {
|
||||||
const psKey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
const psKey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
||||||
return this.context.session.getGroupService().deleteGroupBulletin(GroupCode, psKey, noticeId);
|
return this.context.session.getGroupService().deleteGroupBulletin(groupCode, psKey, noticeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async quitGroupV2(GroupCode: string, needDeleteLocalMsg: boolean) {
|
async quitGroupV2(GroupCode: string, needDeleteLocalMsg: boolean) {
|
||||||
@@ -217,65 +196,42 @@ export class NTQQGroupApi {
|
|||||||
return this.context.session.getGroupService().quitGroupV2(param);
|
return this.context.session.getGroupService().quitGroupV2(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeGroupEssenceBySeq(GroupCode: string, msgRandom: string, msgSeq: string) {
|
async removeGroupEssenceBySeq(groupCode: string, msgRandom: string, msgSeq: string) {
|
||||||
const param = {
|
const param = {
|
||||||
groupCode: GroupCode,
|
groupCode: groupCode,
|
||||||
msgRandom: parseInt(msgRandom),
|
msgRandom: parseInt(msgRandom),
|
||||||
msgSeq: parseInt(msgSeq),
|
msgSeq: parseInt(msgSeq),
|
||||||
};
|
};
|
||||||
return this.context.session.getGroupService().removeGroupEssence(param);
|
return this.context.session.getGroupService().removeGroupEssence(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeGroupEssence(GroupCode: string, msgId: string) {
|
async removeGroupEssence(groupCode: string, msgId: string) {
|
||||||
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
||||||
chatType: 2,
|
chatType: 2,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
peerUid: GroupCode,
|
peerUid: groupCode,
|
||||||
}, msgId, 1, false);
|
}, msgId, 1, false);
|
||||||
const param = {
|
const param = {
|
||||||
groupCode: GroupCode,
|
groupCode: groupCode,
|
||||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
||||||
};
|
};
|
||||||
return this.context.session.getGroupService().removeGroupEssence(param);
|
return this.context.session.getGroupService().removeGroupEssence(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSingleScreenNotifies(doubt: boolean, num: number) {
|
async getSingleScreenNotifies(doubt: boolean, count: number) {
|
||||||
const [, , , notifies] = await this.core.eventWrapper.callNormalEventV2(
|
const [, , , notifies] = await this.core.eventWrapper.callNormalEventV2(
|
||||||
'NodeIKernelGroupService/getSingleScreenNotifies',
|
'NodeIKernelGroupService/getSingleScreenNotifies',
|
||||||
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
|
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
|
||||||
[
|
[
|
||||||
doubt,
|
doubt,
|
||||||
'',
|
'',
|
||||||
num,
|
count,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
return notifies;
|
return notifies;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
|
|
||||||
const Listener = this.core.eventWrapper.registerListen(
|
|
||||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
|
||||||
(params, _, members) => params === GroupCode && members.size > 0,
|
|
||||||
1,
|
|
||||||
forced ? 5000 : 250,
|
|
||||||
);
|
|
||||||
const retData = await (
|
|
||||||
this.core.eventWrapper
|
|
||||||
.createEventFunction('NodeIKernelGroupService/getMemberInfo')
|
|
||||||
)!(GroupCode, [uid], forced);
|
|
||||||
if (retData.result !== 0) {
|
|
||||||
throw new Error(`${retData.errMsg}`);
|
|
||||||
}
|
|
||||||
const result = await Listener as unknown;
|
|
||||||
let member: GroupMember | undefined;
|
|
||||||
if (Array.isArray(result) && result?.[2] instanceof Map) {
|
|
||||||
const members = result[2] as Map<string, GroupMember>;
|
|
||||||
member = members.get(uid);
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
async searchGroup(groupCode: string) {
|
async searchGroup(groupCode: string) {
|
||||||
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
|
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
|
||||||
'NodeIKernelSearchService/searchGroup',
|
'NodeIKernelSearchService/searchGroup',
|
||||||
@@ -294,178 +250,89 @@ export class NTQQGroupApi {
|
|||||||
return ret.groupInfos.find(g => g.groupCode === groupCode);
|
return ret.groupInfos.find(g => g.groupCode === groupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupMemberEx(GroupCode: string, uid: string, forced = false, retry = 2) {
|
async getGroupMemberEx(groupCode: string, uid: string, forced: boolean = false, retry: number = 2) {
|
||||||
const data = await solveAsyncProblem((eventWrapper: NTEventWrapper, GroupCode: string, uid: string, forced = false) => {
|
const data = await solveAsyncProblem((eventWrapper: NTEventWrapper, GroupCode: string, uid: string, forced = false) => {
|
||||||
return eventWrapper.callNormalEventV2(
|
return eventWrapper.callNormalEventV2(
|
||||||
'NodeIKernelGroupService/getMemberInfo',
|
'NodeIKernelGroupService/getMemberInfo',
|
||||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||||
[GroupCode, [uid], forced],
|
[groupCode, [uid], forced],
|
||||||
(ret) => ret.result === 0,
|
(ret) => ret.result === 0,
|
||||||
(params, _, members) => params === GroupCode && members.size > 0 && members.has(uid),
|
(params, _, members) => params === GroupCode && members.size > 0 && members.has(uid),
|
||||||
1,
|
1,
|
||||||
forced ? 2500 : 250
|
forced ? 2500 : 250
|
||||||
);
|
);
|
||||||
}, this.core.eventWrapper, GroupCode, uid, forced);
|
}, this.core.eventWrapper, groupCode, uid, forced);
|
||||||
if (data && data[3] instanceof Map && data[3].has(uid)) {
|
if (data && data[3] instanceof Map && data[3].has(uid)) {
|
||||||
return data[3].get(uid);
|
return data[3].get(uid);
|
||||||
}
|
}
|
||||||
if (retry > 0) {
|
if (retry > 0) {
|
||||||
const trydata = await this.getGroupMemberEx(GroupCode, uid, true, retry - 1) as GroupMember | undefined;
|
const trydata = await this.getGroupMemberEx(groupCode, uid, true, retry - 1) as GroupMember | undefined;
|
||||||
if (trydata) return trydata;
|
if (trydata) return trydata;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async tryGetGroupMembersV2(groupQQ: string, modeListener = false, num = 30, timeout = 100): Promise<{
|
async getGroupFileCount(groupCodes: Array<string>) {
|
||||||
infos: Map<string, GroupMember>;
|
return this.context.session.getRichMediaService().batchGetGroupFileCount(groupCodes);
|
||||||
finish: boolean;
|
|
||||||
hasNext: boolean | undefined;
|
|
||||||
}> {
|
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
|
||||||
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
|
|
||||||
.catch(() => { });
|
|
||||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
|
||||||
if (result.errCode !== 0) {
|
|
||||||
throw new Error('获取群成员列表出错,' + result.errMsg);
|
|
||||||
}
|
|
||||||
let resMode2;
|
|
||||||
if (modeListener) {
|
|
||||||
const ret = (await once)?.[0];
|
|
||||||
if (ret) {
|
|
||||||
resMode2 = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.context.session.getGroupService().destroyMemberListScene(sceneId);
|
|
||||||
return {
|
|
||||||
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
|
|
||||||
finish: result.result.finish,
|
|
||||||
hasNext: resMode2?.hasNext,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetGroupMembersV3(groupQQ: string, num = 3000, timeout = 2500): Promise<{
|
async getArkJsonGroupShare(groupCode: string) {
|
||||||
infos: Map<string, GroupMember>;
|
|
||||||
finish: boolean;
|
|
||||||
hasNext: boolean | undefined;
|
|
||||||
listenerMode: boolean;
|
|
||||||
}> {
|
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
|
||||||
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
|
|
||||||
.catch(() => { });
|
|
||||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
|
||||||
if (result.errCode !== 0) {
|
|
||||||
throw new Error('获取群成员列表出错,' + result.errMsg);
|
|
||||||
}
|
|
||||||
let resMode2;
|
|
||||||
if (result.result.finish && result.result.infos.size === 0) {
|
|
||||||
const ret = (await once)?.[0];
|
|
||||||
if (ret) {
|
|
||||||
resMode2 = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.context.session.getGroupService().destroyMemberListScene(sceneId);
|
|
||||||
return {
|
|
||||||
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
|
|
||||||
finish: result.result.finish,
|
|
||||||
hasNext: resMode2?.hasNext,
|
|
||||||
listenerMode: resMode2?.hasNext !== undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async getGroupMembersV2(groupQQ: string, num = 3000, no_cache: boolean = false): Promise<Map<string, GroupMember>> {
|
|
||||||
if (no_cache) {
|
|
||||||
return (await this.getGroupMemberAll(groupQQ, true)).result.infos;
|
|
||||||
}
|
|
||||||
let res = await this.GetGroupMembersV3(groupQQ, num);
|
|
||||||
let ret = res.infos;
|
|
||||||
if (res.infos.size === 0 && !res.listenerMode) {
|
|
||||||
res = await this.GetGroupMembersV3(groupQQ, num);
|
|
||||||
ret = res.infos;
|
|
||||||
}
|
|
||||||
if (res.infos.size === 0) {
|
|
||||||
ret = (await this.getGroupMemberAll(groupQQ)).result.infos;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
|
||||||
const groupService = this.context.session.getGroupService();
|
|
||||||
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
|
|
||||||
const result = await groupService.getNextMemberList(sceneId, undefined, num);
|
|
||||||
if (result.errCode !== 0) {
|
|
||||||
throw new Error('获取群成员列表出错,' + result.errMsg);
|
|
||||||
}
|
|
||||||
this.context.logger.logDebug(`获取群(${groupQQ})成员列表结果:`, `members: ${result.result.infos.size}`);
|
|
||||||
return result.result.infos;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getGroupFileCount(group_ids: Array<string>) {
|
|
||||||
return this.context.session.getRichMediaService().batchGetGroupFileCount(group_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getArkJsonGroupShare(GroupCode: string) {
|
|
||||||
const ret = await this.core.eventWrapper.callNoListenerEvent(
|
const ret = await this.core.eventWrapper.callNoListenerEvent(
|
||||||
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
|
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
|
||||||
GroupCode,
|
groupCode,
|
||||||
) as GeneralCallResult & { arkJson: string };
|
) as GeneralCallResult & { arkJson: string };
|
||||||
return ret.arkJson;
|
return ret.arkJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
//需要异常处理
|
async uploadGroupBulletinPic(groupCode: string, imageurl: string) {
|
||||||
async uploadGroupBulletinPic(GroupCode: string, imageurl: string) {
|
|
||||||
const _Pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
const _Pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
||||||
return this.context.session.getGroupService().uploadGroupBulletinPic(GroupCode, _Pskey, imageurl);
|
return this.context.session.getGroupService().uploadGroupBulletinPic(groupCode, _Pskey, imageurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleGroupRequest(flag: string, operateType: NTGroupRequestOperateTypes, reason?: string) {
|
async handleGroupRequest(notify: GroupNotify, operateType: NTGroupRequestOperateTypes, reason?: string) {
|
||||||
const flagitem = flag.split('|');
|
|
||||||
const groupCode = flagitem[0];
|
|
||||||
const seq = flagitem[1];
|
|
||||||
const type = parseInt(flagitem[2]);
|
|
||||||
|
|
||||||
return this.context.session.getGroupService().operateSysNotify(
|
return this.context.session.getGroupService().operateSysNotify(
|
||||||
false,
|
false,
|
||||||
{
|
{
|
||||||
operateType: operateType,
|
operateType: operateType,
|
||||||
targetMsg: {
|
targetMsg: {
|
||||||
seq: seq, // 通知序列号
|
seq: notify.seq, // 通知序列号
|
||||||
type: type,
|
type: notify.type,
|
||||||
groupCode: groupCode,
|
groupCode: notify.group.groupCode,
|
||||||
postscript: reason ?? ' ', // 仅传空值可能导致处理失败,故默认给个空格
|
postscript: reason ?? ' ', // 仅传空值可能导致处理失败,故默认给个空格
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async quitGroup(groupQQ: string) {
|
async quitGroup(groupCode: string) {
|
||||||
return this.context.session.getGroupService().quitGroup(groupQQ);
|
return this.context.session.getGroupService().quitGroup(groupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
|
async kickMember(groupCode: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
|
||||||
return this.context.session.getGroupService().kickMember(groupQQ, kickUids, refuseForever, kickReason);
|
return this.context.session.getGroupService().kickMember(groupCode, kickUids, refuseForever, kickReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
async banMember(groupCode: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
||||||
// timeStamp为秒数, 0为解除禁言
|
// timeStamp为秒数, 0为解除禁言
|
||||||
return this.context.session.getGroupService().setMemberShutUp(groupQQ, memList);
|
return this.context.session.getGroupService().setMemberShutUp(groupCode, memList);
|
||||||
}
|
}
|
||||||
|
|
||||||
async banGroup(groupQQ: string, shutUp: boolean) {
|
async banGroup(groupCode: string, shutUp: boolean) {
|
||||||
return this.context.session.getGroupService().setGroupShutUp(groupQQ, shutUp);
|
return this.context.session.getGroupService().setGroupShutUp(groupCode, shutUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
async setMemberCard(groupCode: string, memberUid: string, cardName: string) {
|
||||||
return this.context.session.getGroupService().modifyMemberCardName(groupQQ, memberUid, cardName);
|
return this.context.session.getGroupService().modifyMemberCardName(groupCode, memberUid, cardName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setMemberRole(groupQQ: string, memberUid: string, role: NTGroupMemberRole) {
|
async setMemberRole(groupCode: string, memberUid: string, role: NTGroupMemberRole) {
|
||||||
return this.context.session.getGroupService().modifyMemberRole(groupQQ, memberUid, role);
|
return this.context.session.getGroupService().modifyMemberRole(groupCode, memberUid, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setGroupName(groupQQ: string, groupName: string) {
|
async setGroupName(groupCode: string, groupName: string) {
|
||||||
return this.context.session.getGroupService().modifyGroupName(groupQQ, groupName, false);
|
return this.context.session.getGroupService().modifyGroupName(groupCode, groupName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async publishGroupBulletin(groupQQ: string, content: string, picInfo: {
|
async publishGroupBulletin(groupCode: string, content: string, picInfo: {
|
||||||
id: string,
|
id: string,
|
||||||
width: number,
|
width: number,
|
||||||
height: number
|
height: number
|
||||||
@@ -479,11 +346,11 @@ export class NTQQGroupApi {
|
|||||||
pinned: pinned,
|
pinned: pinned,
|
||||||
confirmRequired: confirmRequired,
|
confirmRequired: confirmRequired,
|
||||||
};
|
};
|
||||||
return this.context.session.getGroupService().publishGroupBulletin(groupQQ, psKey!, data);
|
return this.context.session.getGroupService().publishGroupBulletin(groupCode, psKey!, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupRemainAtTimes(GroupCode: string) {
|
async getGroupRemainAtTimes(groupCode: string) {
|
||||||
return this.context.session.getGroupService().getGroupRemainAtTimes(GroupCode);
|
return this.context.session.getGroupService().getGroupRemainAtTimes(groupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMemberExtInfo(groupCode: string, uin: string) {
|
async getMemberExtInfo(groupCode: string, uin: string) {
|
||||||
|
@@ -31,7 +31,7 @@ export class NTQQPacketApi {
|
|||||||
await this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
await this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
||||||
.then()
|
.then()
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.logger.logError.bind(this.core.context.logger);
|
this.logger.logError(err);
|
||||||
this.errStack.push(err);
|
this.errStack.push(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@ import { ModifyProfileParams, User, UserDetailSource } from '@/core/types';
|
|||||||
import { RequestUtil } from '@/common/request';
|
import { RequestUtil } from '@/common/request';
|
||||||
import { InstanceContext, NapCatCore, ProfileBizType } from '..';
|
import { InstanceContext, NapCatCore, ProfileBizType } from '..';
|
||||||
import { solveAsyncProblem } from '@/common/helper';
|
import { solveAsyncProblem } from '@/common/helper';
|
||||||
|
import { promisify } from 'node:util';
|
||||||
|
import { LRUCache } from '@/common/lru-cache';
|
||||||
|
|
||||||
export class NTQQUserApi {
|
export class NTQQUserApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
@@ -11,13 +13,15 @@ export class NTQQUserApi {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
//self_tind格式
|
|
||||||
async createUidFromTinyId(tinyId: string) {
|
async getCoreAndBaseInfo(uids: string[]) {
|
||||||
return this.context.session.getMsgService().createUidFromTinyId(this.core.selfInfo.uin, tinyId);
|
return await this.core.eventWrapper.callNoListenerEvent(
|
||||||
}
|
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
||||||
async getStatusByUid(uid: string) {
|
'nodeStore',
|
||||||
return this.context.session.getProfileService().getStatus(uid);
|
uids,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认获取自己的 type = 2 获取别人 type = 1
|
// 默认获取自己的 type = 2 获取别人 type = 1
|
||||||
async getProfileLike(uid: string, start: number, count: number, type: number = 2) {
|
async getProfileLike(uid: string, start: number, count: number, type: number = 2) {
|
||||||
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
||||||
@@ -161,35 +165,51 @@ export class NTQQUserApi {
|
|||||||
if (!skey) {
|
if (!skey) {
|
||||||
throw new Error('SKey is Empty');
|
throw new Error('SKey is Empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
return skey;
|
return skey;
|
||||||
}
|
}
|
||||||
|
|
||||||
//后期改成流水线处理
|
|
||||||
async getUidByUinV2(Uin: string) {
|
async getUidByUinV2(Uin: string) {
|
||||||
let uid = (await this.context.session.getGroupService().getUidByUins([Uin])).uids.get(Uin);
|
if (!Uin) {
|
||||||
if (uid) return uid;
|
return '';
|
||||||
uid = (await this.context.session.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])).get(Uin);
|
}
|
||||||
if (uid) return uid;
|
const services = [
|
||||||
uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
|
() => this.context.session.getUixConvertService().getUid([Uin]).then((data) => data.uidInfo.get(Uin)).catch(() => undefined),
|
||||||
if (uid) return uid;
|
() => promisify<string, string[], Map<string, string>>
|
||||||
const unverifiedUid = (await this.getUserDetailInfoByUin(Uin)).detail.uid;//从QQ Native 特殊转换
|
(this.context.session.getProfileService().getUidByUin)('FriendsServiceImpl', [Uin]).then((data) => data.get(Uin)).catch(() => undefined),
|
||||||
if (unverifiedUid.indexOf('*') == -1) uid = unverifiedUid;
|
() => this.context.session.getGroupService().getUidByUins([Uin]).then((data) => data.uids.get(Uin)).catch(() => undefined),
|
||||||
//if (uid) return uid;
|
() => this.getUserDetailInfoByUin(Uin).then((data) => data.detail.uid).catch(() => undefined),
|
||||||
return uid;
|
];
|
||||||
|
let uid: string | undefined = undefined;
|
||||||
|
for (const service of services) {
|
||||||
|
uid = await service();
|
||||||
|
if (uid && uid.indexOf('*') == -1 && uid !== '') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uid ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
//后期改成流水线处理
|
|
||||||
async getUinByUidV2(Uid: string) {
|
async getUinByUidV2(Uid: string) {
|
||||||
let uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
|
if (!Uid) {
|
||||||
if (uin) return uin;
|
return '0';
|
||||||
uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
|
}
|
||||||
if (uin) return uin;
|
const services = [
|
||||||
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
|
() => this.context.session.getUixConvertService().getUin([Uid]).then((data) => data.uinInfo.get(Uid)).catch(() => undefined),
|
||||||
if (uin) return uin;
|
() => this.context.session.getGroupService().getUinByUids([Uid]).then((data) => data.uins.get(Uid)).catch(() => undefined),
|
||||||
uin = (await this.core.apis.FriendApi.getBuddyIdMap(true)).getKey(Uid);
|
() => promisify<string, string[], Map<string, string>>
|
||||||
if (uin) return uin;
|
(this.context.session.getProfileService().getUinByUid)('FriendsServiceImpl', [Uid]).then((data) => data.get(Uid)).catch(() => undefined),
|
||||||
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
() => this.core.apis.FriendApi.getBuddyIdMap(true).then((data) => data.getKey(Uid)).catch(() => undefined),
|
||||||
return uin;
|
() => this.getUserDetailInfo(Uid).then((data) => data.uin).catch(() => undefined),
|
||||||
|
];
|
||||||
|
let uin: string | undefined = undefined;
|
||||||
|
for (const service of services) {
|
||||||
|
uin = await service();
|
||||||
|
if (uin && uin !== '0' && uin !== '') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uin ?? '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecentContactListSnapShot(count: number) {
|
async getRecentContactListSnapShot(count: number) {
|
||||||
|
14
src/core/external/appid.json
vendored
14
src/core/external/appid.json
vendored
@@ -98,5 +98,17 @@
|
|||||||
"6.9.61-29927": {
|
"6.9.61-29927": {
|
||||||
"appid": 537255836,
|
"appid": 537255836,
|
||||||
"qua": "V1_MAC_NQ_6.9.61_29927_GW_B"
|
"qua": "V1_MAC_NQ_6.9.61_29927_GW_B"
|
||||||
|
},
|
||||||
|
"9.9.17-30366": {
|
||||||
|
"appid": 537258389,
|
||||||
|
"qua": "V1_WIN_NQ_9.9.17_30366_GW_B"
|
||||||
|
},
|
||||||
|
"3.2.15-30366": {
|
||||||
|
"appid": 537258413,
|
||||||
|
"qua": "V1_LNX_NQ_3.2.15_30366_GW_B"
|
||||||
|
},
|
||||||
|
"6.9.62-30366": {
|
||||||
|
"appid": 537258401,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.62_30366_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
22
src/core/external/offset.json
vendored
22
src/core/external/offset.json
vendored
@@ -102,5 +102,25 @@
|
|||||||
"6.9.61-29927-arm64": {
|
"6.9.61-29927-arm64": {
|
||||||
"send": "4038740",
|
"send": "4038740",
|
||||||
"recv": "403AF58"
|
"recv": "403AF58"
|
||||||
|
},
|
||||||
|
"9.9.17-30366-x64": {
|
||||||
|
"send": "39AB0B0",
|
||||||
|
"recv": "39AF4E4"
|
||||||
|
},
|
||||||
|
"3.2.15-30366-x64": {
|
||||||
|
"send": "A402380",
|
||||||
|
"recv": "A405C80"
|
||||||
|
},
|
||||||
|
"3.2.15-30366-arm64": {
|
||||||
|
"send": "70C3FA8",
|
||||||
|
"recv": "70C77E0"
|
||||||
|
},
|
||||||
|
"6.9.62-30366-x64": {
|
||||||
|
"send": "4669760",
|
||||||
|
"recv": "466BFCC"
|
||||||
|
},
|
||||||
|
"6.9.62-30366-arm64": {
|
||||||
|
"send": "4189770",
|
||||||
|
"recv": "418BF88"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
import * as fileType from 'file-type';
|
import { fileTypeFromFile } from 'file-type';
|
||||||
import { PicType } from '../types';
|
import { PicType } from '../types';
|
||||||
export async function getFileTypeForSendType(picPath: string): Promise<PicType> {
|
export async function getFileTypeForSendType(picPath: string): Promise<PicType> {
|
||||||
const fileTypeResult = (await fileType.fileTypeFromFile(picPath))?.ext ?? 'jpg';
|
const fileTypeResult = (await fileTypeFromFile(picPath))?.ext ?? 'jpg';
|
||||||
const picTypeMap: { [key: string]: PicType } = {
|
const picTypeMap: { [key: string]: PicType } = {
|
||||||
//'webp': PicType.NEWPIC_WEBP,
|
//'webp': PicType.NEWPIC_WEBP,
|
||||||
'gif': PicType.NEWPIC_GIF,
|
'gif': PicType.NEWPIC_GIF,
|
||||||
|
@@ -27,7 +27,6 @@ export class RkeyManager {
|
|||||||
await this.refreshRkey();
|
await this.refreshRkey();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||||
//this.logger.logError.bind(this.logger)('获取rkey失败', e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.rkeyData;
|
return this.rkeyData;
|
||||||
@@ -50,7 +49,7 @@ export class RkeyManager {
|
|||||||
expired_time: temp.expired_time
|
expired_time: temp.expired_time
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.logError.bind(this.logger)(`[Rkey] Get Rkey ${url} Error `, e);
|
this.logger.logError(`[Rkey] Get Rkey ${url} Error `, e);
|
||||||
//是否为最后一个url
|
//是否为最后一个url
|
||||||
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
||||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||||
|
@@ -24,10 +24,10 @@ import path from 'node:path';
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { hostname, systemName, systemVersion } from '@/common/system';
|
import { hostname, systemName, systemVersion } from '@/common/system';
|
||||||
import { NTEventWrapper } from '@/common/event';
|
import { NTEventWrapper } from '@/common/event';
|
||||||
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types';
|
import { GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types';
|
||||||
import { NapCatConfigLoader } from '@/core/helper/config';
|
import { NapCatConfigLoader } from '@/core/helper/config';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
|
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
|
||||||
import { proxiedListenerOf } from '@/common/proxy-handler';
|
import { proxiedListenerOf } from '@/common/proxy-handler';
|
||||||
import { NTQQPacketApi } from './apis/packet';
|
import { NTQQPacketApi } from './apis/packet';
|
||||||
export * from './wrapper';
|
export * from './wrapper';
|
||||||
@@ -127,7 +127,7 @@ export class NapCatCore {
|
|||||||
await api.initApi();
|
await api.initApi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
|
this.initNapCatCoreListeners().then().catch((e) => this.context.logger.logError(e));
|
||||||
|
|
||||||
this.context.logger.setFileLogEnabled(
|
this.context.logger.setFileLogEnabled(
|
||||||
this.configLoader.configData.fileLog,
|
this.configLoader.configData.fileLog,
|
||||||
@@ -154,7 +154,7 @@ export class NapCatCore {
|
|||||||
const msgListener = new NodeIKernelMsgListener();
|
const msgListener = new NodeIKernelMsgListener();
|
||||||
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
||||||
// 下线通知
|
// 下线通知
|
||||||
this.context.logger.logError.bind(this.context.logger)('[KickedOffLine] [' + Info.tipsTitle + '] ' + Info.tipsDesc);
|
this.context.logger.logError('[KickedOffLine] [' + Info.tipsTitle + '] ' + Info.tipsDesc);
|
||||||
this.selfInfo.online = false;
|
this.selfInfo.online = false;
|
||||||
};
|
};
|
||||||
msgListener.onRecvMsg = (msgs) => {
|
msgListener.onRecvMsg = (msgs) => {
|
||||||
@@ -163,7 +163,6 @@ export class NapCatCore {
|
|||||||
msgListener.onAddSendMsg = (msg) => {
|
msgListener.onAddSendMsg = (msg) => {
|
||||||
this.context.logger.logMessage(msg, this.selfInfo);
|
this.context.logger.logMessage(msg, this.selfInfo);
|
||||||
};
|
};
|
||||||
//await sleep(2500);
|
|
||||||
this.context.session.getMsgService().addKernelMsgListener(
|
this.context.session.getMsgService().addKernelMsgListener(
|
||||||
proxiedListenerOf(msgListener, this.context.logger),
|
proxiedListenerOf(msgListener, this.context.logger),
|
||||||
);
|
);
|
||||||
@@ -185,92 +184,6 @@ export class NapCatCore {
|
|||||||
this.context.session.getProfileService().addKernelProfileListener(
|
this.context.session.getProfileService().addKernelProfileListener(
|
||||||
proxiedListenerOf(profileListener, this.context.logger),
|
proxiedListenerOf(profileListener, this.context.logger),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 群相关
|
|
||||||
const groupListener = new NodeIKernelGroupListener();
|
|
||||||
groupListener.onGroupListUpdate = (updateType, groupList) => {
|
|
||||||
// console.log("onGroupListUpdate", updateType, groupList)
|
|
||||||
groupList.map(g => {
|
|
||||||
const existGroup = this.apis.GroupApi.groupCache.get(g.groupCode);
|
|
||||||
//群成员数量变化 应该刷新缓存
|
|
||||||
if (existGroup && g.memberCount === existGroup.memberCount) {
|
|
||||||
Object.assign(existGroup, g);
|
|
||||||
} else {
|
|
||||||
this.apis.GroupApi.groupCache.set(g.groupCode, g);
|
|
||||||
// 获取群成员
|
|
||||||
}
|
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(g.groupCode, 'groupMemberList_MainWindow');
|
|
||||||
this.context.session.getGroupService().getNextMemberList(sceneId, undefined, 3000).then( /* r => {
|
|
||||||
// console.log(`get group ${g.groupCode} members`, r);
|
|
||||||
// r.result.infos.forEach(member => {
|
|
||||||
// });
|
|
||||||
// groupMembers.set(g.groupCode, r.result.infos);
|
|
||||||
} */);
|
|
||||||
this.context.session.getGroupService().destroyMemberListScene(sceneId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
groupListener.onMemberListChange = (arg) => {
|
|
||||||
// TODO: 应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
|
||||||
const groupCode = arg.sceneId.split('_')[0];
|
|
||||||
if (this.apis.GroupApi.groupMemberCache.has(groupCode)) {
|
|
||||||
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode)!;
|
|
||||||
arg.infos.forEach((member, uid) => {
|
|
||||||
//console.log('onMemberListChange', member);
|
|
||||||
const existMember = existMembers.get(uid);
|
|
||||||
if (existMember) {
|
|
||||||
Object.assign(existMember, member);
|
|
||||||
} else {
|
|
||||||
existMembers.set(uid, member);
|
|
||||||
}
|
|
||||||
//移除成员
|
|
||||||
if (member.isDelete) {
|
|
||||||
existMembers.delete(uid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.apis.GroupApi.groupMemberCache.set(groupCode, arg.infos);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
groupListener.onMemberInfoChange = (groupCode, dataSource, members) => {
|
|
||||||
if (dataSource === DataSource.LOCAL && members.get(this.selfInfo.uid)?.isDelete) {
|
|
||||||
// 自身退群或者被踢退群 5s用于Api操作 之后不再出现
|
|
||||||
setTimeout(() => {
|
|
||||||
this.apis.GroupApi.groupCache.delete(groupCode);
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
}
|
|
||||||
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode);
|
|
||||||
if (existMembers) {
|
|
||||||
members.forEach((member, uid) => {
|
|
||||||
const existMember = existMembers.get(uid);
|
|
||||||
if (existMember) {
|
|
||||||
// 检查管理变动
|
|
||||||
member.isChangeRole = this.checkAdminEvent(groupCode, member, existMember);
|
|
||||||
// 更新成员信息
|
|
||||||
Object.assign(existMember, member);
|
|
||||||
} else {
|
|
||||||
existMembers.set(uid, member);
|
|
||||||
}
|
|
||||||
//移除成员
|
|
||||||
if (member.isDelete) {
|
|
||||||
existMembers.delete(uid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.apis.GroupApi.groupMemberCache.set(groupCode, members);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.context.session.getGroupService().addKernelGroupListener(
|
|
||||||
proxiedListenerOf(groupListener, this.context.logger),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
|
|
||||||
if (memberNew.role !== memberOld?.role) {
|
|
||||||
this.context.logger.logDebug(`群 ${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
src/core/packet/transformer/proto/message/groupAdmin.ts
Normal file
18
src/core/packet/transformer/proto/message/groupAdmin.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { ProtoField, ScalarType } from "@napneko/nap-proto-core";
|
||||||
|
|
||||||
|
export const GroupAdminExtra = {
|
||||||
|
adminUid: ProtoField(1, ScalarType.STRING),
|
||||||
|
isPromote: ProtoField(2, ScalarType.BOOL),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupAdminBody = {
|
||||||
|
extraDisable: ProtoField(1, () => GroupAdminExtra),
|
||||||
|
extraEnable: ProtoField(2, () => GroupAdminExtra),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupAdmin = {
|
||||||
|
groupUin: ProtoField(1, ScalarType.UINT32),
|
||||||
|
flag: ProtoField(2, ScalarType.UINT32),
|
||||||
|
isPromote: ProtoField(3, ScalarType.BOOL),
|
||||||
|
body: ProtoField(4, () => GroupAdminBody),
|
||||||
|
}
|
@@ -62,7 +62,7 @@ export const GroupChange = {
|
|||||||
operatorUid: ProtoField(5, ScalarType.STRING, true),
|
operatorUid: ProtoField(5, ScalarType.STRING, true),
|
||||||
increaseType: ProtoField(6, ScalarType.UINT32),
|
increaseType: ProtoField(6, ScalarType.UINT32),
|
||||||
field7: ProtoField(7, ScalarType.BYTES, true),
|
field7: ProtoField(7, ScalarType.BYTES, true),
|
||||||
}
|
};
|
||||||
|
|
||||||
export const PushMsgBody = {
|
export const PushMsgBody = {
|
||||||
responseHead: ProtoField(1, () => ResponseHead),
|
responseHead: ProtoField(1, () => ResponseHead),
|
||||||
|
@@ -163,7 +163,7 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
getGroupPortrait(): void;
|
getGroupPortrait(): void;
|
||||||
|
|
||||||
modifyGroupName(groupCode: string, groupName: string, arg: false): void;
|
modifyGroupName(groupCode: string, groupName: string, isNormalMember: boolean): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
modifyGroupRemark(groupCode: string, remark: string): void;
|
modifyGroupRemark(groupCode: string, remark: string): void;
|
||||||
|
|
||||||
@@ -187,13 +187,13 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
destroyGroup(groupCode: string): void;
|
destroyGroup(groupCode: string): void;
|
||||||
|
|
||||||
getSingleScreenNotifies(doubted: boolean, start_seq: string, num: number): Promise<GeneralCallResult>;
|
getSingleScreenNotifies(doubt: boolean, startSeq: string, count: number): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
clearGroupNotifies(groupCode: string): void;
|
clearGroupNotifies(groupCode: string): void;
|
||||||
|
|
||||||
getGroupNotifiesUnreadCount(unknown: boolean): Promise<GeneralCallResult>;
|
getGroupNotifiesUnreadCount(doubt: boolean): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
clearGroupNotifiesUnreadCount(unknown: boolean): void;
|
clearGroupNotifiesUnreadCount(doubt: boolean): void;
|
||||||
|
|
||||||
operateSysNotify(
|
operateSysNotify(
|
||||||
doubt: boolean,
|
doubt: boolean,
|
||||||
|
@@ -4,14 +4,14 @@ import { GeneralCallResult } from '@/core/services/common';
|
|||||||
|
|
||||||
export interface NodeIKernelProfileService {
|
export interface NodeIKernelProfileService {
|
||||||
getOtherFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getOtherFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getVasInfo(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getVasInfo(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getRelationFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getRelationFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string, string>>;
|
getUidByUin(callfrom: string, uin: Array<string>): Map<string, string>;
|
||||||
|
|
||||||
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string, string>>;
|
getUinByUid(callfrom: string, uid: Array<string>): Map<string, string>;
|
||||||
|
|
||||||
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
|
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@ export interface TextElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FaceElement {
|
export interface FaceElement {
|
||||||
|
pokeType?: number;
|
||||||
faceIndex: number;
|
faceIndex: number;
|
||||||
faceType: FaceType;
|
faceType: FaceType;
|
||||||
faceText?: string;
|
faceText?: string;
|
||||||
|
@@ -1,6 +1,16 @@
|
|||||||
//LiteLoader需要提供部分IPC接口,以便于其他插件调用
|
//LiteLoader需要提供部分IPC接口,以便于其他插件调用
|
||||||
const { ipcMain } = require('electron');
|
const { ipcMain } = require('electron');
|
||||||
const napcat = require('./napcat.cjs');
|
const napcat = require('./napcat.cjs');
|
||||||
|
const { shell } = require('electron');
|
||||||
ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
|
ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
|
||||||
return napcat.NCgetWebUiUrl();
|
return napcat.NCgetWebUiUrl();
|
||||||
});
|
});
|
||||||
|
ipcMain.on('open_external_url', (event, url) => {
|
||||||
|
shell.openExternal(url);
|
||||||
|
});
|
||||||
|
ipcMain.handle('napcat_get_reactweb', async (event, arg) => {
|
||||||
|
let url = new URL(await napcat.NCgetWebUiUrl());
|
||||||
|
let port = url.port;
|
||||||
|
let token = url.searchParams.get('token');
|
||||||
|
return `https://napcat.152710.xyz/web_login?back=http://127.0.0.1:${port}&token=${token}`;
|
||||||
|
});
|
@@ -58,7 +58,7 @@ export async function NCoreInitFramework(
|
|||||||
await loaderObject.core.initCore();
|
await loaderObject.core.initCore();
|
||||||
|
|
||||||
//启动WebUi
|
//启动WebUi
|
||||||
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
InitWebUi(logger, pathWrapper).then().catch(e => logger.logError(e));
|
||||||
//初始化LLNC的Onebot实现
|
//初始化LLNC的Onebot实现
|
||||||
await new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper).InitOneBot();
|
await new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper).InitOneBot();
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
const { contextBridge } = require('electron');
|
const { contextBridge, ipcRenderer } = require('electron');
|
||||||
const { ipcRenderer } = require('electron');
|
|
||||||
|
|
||||||
const napcat = {
|
const napcat = {
|
||||||
getWebUiUrl: async () => {
|
getWebUiUrl: async () => {
|
||||||
return ipcRenderer.invoke('napcat_get_webtoken');
|
return ipcRenderer.invoke('napcat_get_webtoken');
|
||||||
},
|
},
|
||||||
|
openExternalUrl: async (url) => {
|
||||||
|
ipcRenderer.send('open_external_url', url);
|
||||||
|
},
|
||||||
|
getWebUiUrlReact: async () => {
|
||||||
|
return ipcRenderer.invoke('napcat_get_reactweb');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 在window对象下导出只读对象
|
// 在window对象下导出只读对象
|
||||||
contextBridge.exposeInMainWorld('napcat', napcat);
|
contextBridge.exposeInMainWorld('napcat', napcat);
|
@@ -1,27 +1,20 @@
|
|||||||
export const onSettingWindowCreated = async (view) => {
|
export const onSettingWindowCreated = async (view) => {
|
||||||
|
|
||||||
// view.style.width = "100%";
|
|
||||||
// view.style.height = "100%";
|
|
||||||
// //添加iframe
|
|
||||||
// const iframe = document.createElement("iframe");
|
|
||||||
// iframe.src = await window.napcat.getWebUiUrl();
|
|
||||||
// iframe.width = "100%";
|
|
||||||
// iframe.height = "100%";
|
|
||||||
// iframe.style.border = "none";
|
|
||||||
// //去掉iframe滚动条
|
|
||||||
// //iframe.scrolling = "no";
|
|
||||||
// //有滚动条何尝不是一种美
|
|
||||||
// view.appendChild(iframe);
|
|
||||||
let webui = await window.napcat.getWebUiUrl();
|
let webui = await window.napcat.getWebUiUrl();
|
||||||
|
let webuiReact = await window.napcat.getWebUiUrlReact();
|
||||||
view.innerHTML = `
|
view.innerHTML = `
|
||||||
<setting-section data-title="">
|
<setting-section data-title="">
|
||||||
<setting-panel>
|
<setting-panel>
|
||||||
<setting-list data-direction="column">
|
<setting-list data-direction="column">
|
||||||
<setting-item>
|
<setting-item>
|
||||||
<setting-button data-type="primary" class="nc_openwebui">打开配置页面</setting-button>
|
<setting-button data-type="primary" class="nc_openwebui">在QQ内打开配置页面(VUE)</setting-button>
|
||||||
|
<setting-button data-type="primary" class="nc_openwebui_ex">在默认浏览器打开配置页面(VUE)</setting-button>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item>
|
||||||
|
<setting-button data-type="primary" class="nc_openwebui_ex_react">在默认浏览器打开配置页面(React)</setting-button>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
<setting-item>
|
<setting-item>
|
||||||
<div>
|
<div>
|
||||||
|
<setting-text>WebUi远程地址可以点击下方复制哦~</setting-text>
|
||||||
<setting-text class="nc_webui">WebUi</setting-text>
|
<setting-text class="nc_webui">WebUi</setting-text>
|
||||||
</div>
|
</div>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
@@ -29,8 +22,27 @@ export const onSettingWindowCreated = async (view) => {
|
|||||||
</setting-panel>
|
</setting-panel>
|
||||||
</setting-section>
|
</setting-section>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
view.querySelector('.nc_openwebui').addEventListener('click', () => {
|
view.querySelector('.nc_openwebui').addEventListener('click', () => {
|
||||||
window.open(webui, '_blank');
|
window.open(webui, '_blank');
|
||||||
});
|
});
|
||||||
|
view.querySelector('.nc_openwebui_ex').addEventListener('click', () => {
|
||||||
|
window.napcat.openExternalUrl(webui);
|
||||||
|
});
|
||||||
|
|
||||||
|
view.querySelector('.nc_openwebui_ex_react').addEventListener('click', () => {
|
||||||
|
window.napcat.openExternalUrl(webuiReact);
|
||||||
|
});
|
||||||
|
|
||||||
view.querySelector('.nc_webui').innerText = webui;
|
view.querySelector('.nc_webui').innerText = webui;
|
||||||
};
|
|
||||||
|
// 添加点击复制功能
|
||||||
|
view.querySelector('.nc_webui').addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(webui);
|
||||||
|
alert('WebUi URL 已复制到剪贴板');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('复制到剪贴板失败: ', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@@ -42,7 +42,7 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
|||||||
|
|
||||||
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
|
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
|
||||||
if (this.payloadSchema) {
|
if (this.payloadSchema) {
|
||||||
this.validate = new Ajv({ allowUnionTypes: true }).compile(this.payloadSchema);
|
this.validate = new Ajv({ allowUnionTypes: true, useDefaults: true }).compile(this.payloadSchema);
|
||||||
}
|
}
|
||||||
if (this.validate && !this.validate(payload)) {
|
if (this.validate && !this.validate(payload)) {
|
||||||
const errors = this.validate.errors as ErrorObject[];
|
const errors = this.validate.errors as ErrorObject[];
|
||||||
|
@@ -1,17 +1,13 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
rawData: Type.String(),
|
||||||
properties: {
|
brief: Type.String(),
|
||||||
rawData: { type: 'string' },
|
});
|
||||||
brief: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['brief', 'rawData'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class CreateCollection extends OneBotAction<Payload, any> {
|
export class CreateCollection extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.CreateCollection;
|
actionName = ActionName.CreateCollection;
|
||||||
@@ -25,4 +21,4 @@ export class CreateCollection extends OneBotAction<Payload, any> {
|
|||||||
payload.brief, payload.rawData,
|
payload.brief, payload.rawData,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,23 +1,19 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
count: Type.Union([Type.Number(), Type.String()], { default: 48 }),
|
||||||
properties: {
|
});
|
||||||
count: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class FetchCustomFace extends OneBotAction<Payload, string[]> {
|
export class FetchCustomFace extends OneBotAction<Payload, string[]> {
|
||||||
actionName = ActionName.FetchCustomFace;
|
actionName = ActionName.FetchCustomFace;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
|
const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+payload.count);
|
||||||
const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+(payload.count ?? 48));
|
|
||||||
return ret.emojiInfoList.map(e => e.url);
|
return ret.emojiInfoList.map(e => e.url);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,32 +1,27 @@
|
|||||||
//getMsgEmojiLikesList
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
message_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
emojiId: Type.Union([Type.Number(), Type.String()]),
|
||||||
user_id: { type: 'string' },
|
emojiType: Type.Union([Type.Number(), Type.String()]),
|
||||||
group_id: { type: 'string' },
|
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
|
||||||
emojiId: { type: 'string' },
|
});
|
||||||
emojiType: { type: 'string' },
|
|
||||||
message_id: { type: ['string', 'number'] },
|
|
||||||
count: { type: ['string', 'number'] },
|
|
||||||
},
|
|
||||||
required: ['emojiId', 'emojiType', 'message_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class FetchEmojiLike extends OneBotAction<Payload, any> {
|
export class FetchEmojiLike extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.FetchEmojiLike;
|
actionName = ActionName.FetchEmojiLike;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||||
if (!msgIdPeer) throw new Error('消息不存在');
|
if (!msgIdPeer) throw new Error('消息不存在');
|
||||||
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
|
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
|
||||||
return await this.core.apis.MsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, +(payload.count ?? 20));
|
return await this.core.apis.MsgApi.getMsgEmojiLikesList(
|
||||||
|
msgIdPeer.Peer, msg.msgSeq, payload.emojiId.toString(), payload.emojiType.toString(), +payload.count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,17 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
|
||||||
export class FetchUserProfileLike extends OneBotAction<{ qq: number }, any> {
|
const SchemaData = Type.Object({
|
||||||
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class FetchUserProfileLike extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.FetchUserProfileLike;
|
actionName = ActionName.FetchUserProfileLike;
|
||||||
|
|
||||||
async _handle(payload: { qq: number }) {
|
async _handle(payload: Payload) {
|
||||||
if (!payload.qq) throw new Error('qq is required');
|
return await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
return await this.core.apis.UserApi.getUidByUinV2(payload.qq.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
||||||
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
chat_type: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }),
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
chat_type: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
interface GetAiCharactersResponse {
|
interface GetAiCharactersResponse {
|
||||||
type: string;
|
type: string;
|
||||||
@@ -28,7 +24,7 @@ export class GetAiCharacters extends GetPacketStatusDepends<Payload, GetAiCharac
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, +(payload.chat_type ?? 1) as AIVoiceChatType);
|
const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, +payload.chat_type as AIVoiceChatType);
|
||||||
return rawList?.map((item) => ({
|
return rawList?.map((item) => ({
|
||||||
type: item.category,
|
type: item.category,
|
||||||
characters: item.voices.map((voice) => ({
|
characters: item.voices.map((voice) => ({
|
||||||
|
@@ -1,23 +1,19 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
category: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
count: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }),
|
||||||
category: { type: ['number', 'string'] },
|
});
|
||||||
count: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['category', 'count'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetCollectionList extends OneBotAction<Payload, any> {
|
export class GetCollectionList extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GetCollectionList;
|
actionName = ActionName.GetCollectionList;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
return await this.core.apis.CollectionApi.getAllCollection(parseInt(payload.category.toString()), +(payload.count ?? 1));
|
return await this.core.apis.CollectionApi.getAllCollection(+payload.category, +payload.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,33 +1,37 @@
|
|||||||
import { GroupNotifyMsgStatus } from '@/core';
|
import { GroupNotifyMsgStatus } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { Notify } from '@/onebot/types';
|
||||||
|
|
||||||
interface OB11GroupRequestNotify {
|
export default class GetGroupAddRequest extends OneBotAction<null, Notify[] | null> {
|
||||||
group_id: number,
|
|
||||||
user_id: number,
|
|
||||||
flag: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class GetGroupAddRequest extends OneBotAction<null, OB11GroupRequestNotify[] | null> {
|
|
||||||
actionName = ActionName.GetGroupIgnoreAddRequest;
|
actionName = ActionName.GetGroupIgnoreAddRequest;
|
||||||
|
|
||||||
async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
|
async _handle(payload: null): Promise<Notify[] | null> {
|
||||||
const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
|
const NTQQUserApi = this.core.apis.UserApi;
|
||||||
const retData: any = {
|
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||||
join_requests: await Promise.all(
|
const ignoredNotifies = await NTQQGroupApi.getSingleScreenNotifies(true, 10);
|
||||||
ignoredNotifies
|
const retData: Notify[] = [];
|
||||||
.filter(notify => notify.type === 7)
|
|
||||||
.map(async SSNotify => ({
|
const notifyPromises = ignoredNotifies
|
||||||
request_id: SSNotify.seq,
|
.filter(notify => notify.type === 7)
|
||||||
requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
|
.map(async SSNotify => {
|
||||||
requester_nick: SSNotify.user1?.nickName,
|
const invitorUin = SSNotify.user1?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||||
group_id: SSNotify.group?.groupCode,
|
const actorUin = SSNotify.user2?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||||
group_name: SSNotify.group?.groupName,
|
retData.push({
|
||||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
request_id: +SSNotify.seq,
|
||||||
actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
invitor_uin: invitorUin,
|
||||||
}))),
|
invitor_nick: SSNotify.user1?.nickName,
|
||||||
};
|
group_id: +SSNotify.group?.groupCode,
|
||||||
|
message: SSNotify?.postscript,
|
||||||
|
group_name: SSNotify.group?.groupName,
|
||||||
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
|
actor: actorUin,
|
||||||
|
requester_nick: SSNotify.user1?.nickName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(notifyPromises);
|
||||||
|
|
||||||
return retData;
|
return retData;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,16 +1,11 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
});
|
||||||
|
|
||||||
const SchemaData = {
|
type Payload = Static<typeof SchemaData>;
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GetGroupInfoEx extends OneBotAction<Payload, any> {
|
export class GetGroupInfoEx extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GetGroupInfoEx;
|
actionName = ActionName.GetGroupInfoEx;
|
||||||
|
@@ -1,47 +1,37 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import { MiniAppInfo, MiniAppInfoHelper } from "@/core/packet/utils/helper/miniAppHelper";
|
import { MiniAppInfo, MiniAppInfoHelper } from "@/core/packet/utils/helper/miniAppHelper";
|
||||||
import { MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams } from "@/core/packet/entities/miniApp";
|
import { MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams } from "@/core/packet/entities/miniApp";
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Union([
|
||||||
type: 'object',
|
Type.Object({
|
||||||
properties: {
|
type: Type.Union([Type.Literal('bili'), Type.Literal('weibo')]),
|
||||||
type: {
|
title: Type.String(),
|
||||||
type: 'string',
|
desc: Type.String(),
|
||||||
enum: ['bili', 'weibo']
|
picUrl: Type.String(),
|
||||||
},
|
jumpUrl: Type.String(),
|
||||||
title: { type: 'string' },
|
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
|
||||||
desc: { type: 'string' },
|
}),
|
||||||
picUrl: { type: 'string' },
|
Type.Object({
|
||||||
jumpUrl: { type: 'string' },
|
title: Type.String(),
|
||||||
iconUrl: { type: 'string' },
|
desc: Type.String(),
|
||||||
sdkId: { type: 'string' },
|
picUrl: Type.String(),
|
||||||
appId: { type: 'string' },
|
jumpUrl: Type.String(),
|
||||||
scene: { type: ['number', 'string'] },
|
iconUrl: Type.String(),
|
||||||
templateType: { type: ['number', 'string'] },
|
appId: Type.String(),
|
||||||
businessType: { type: ['number', 'string'] },
|
scene: Type.Union([Type.Number(), Type.String()]),
|
||||||
verType: { type: ['number', 'string'] },
|
templateType: Type.Union([Type.Number(), Type.String()]),
|
||||||
shareType: { type: ['number', 'string'] },
|
businessType: Type.Union([Type.Number(), Type.String()]),
|
||||||
versionId: { type: 'string' },
|
verType: Type.Union([Type.Number(), Type.String()]),
|
||||||
withShareTicket: { type: ['number', 'string'] },
|
shareType: Type.Union([Type.Number(), Type.String()]),
|
||||||
rawArkData: { type: ['boolean', 'string'] }
|
versionId: Type.String(),
|
||||||
},
|
sdkId: Type.String(),
|
||||||
oneOf: [
|
withShareTicket: Type.Union([Type.Number(), Type.String()]),
|
||||||
{
|
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
|
||||||
required: ['type', 'title', 'desc', 'picUrl', 'jumpUrl']
|
})
|
||||||
},
|
]);
|
||||||
{
|
type Payload = Static<typeof SchemaData>;
|
||||||
required: [
|
|
||||||
'title', 'desc', 'picUrl', 'jumpUrl',
|
|
||||||
'iconUrl', 'appId', 'scene', 'templateType', 'businessType',
|
|
||||||
'verType', 'shareType', 'versionId', 'withShareTicket'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
||||||
data: MiniAppData | MiniAppRawData
|
data: MiniAppData | MiniAppRawData
|
||||||
@@ -57,7 +47,7 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
|||||||
picUrl: payload.picUrl,
|
picUrl: payload.picUrl,
|
||||||
jumpUrl: payload.jumpUrl
|
jumpUrl: payload.jumpUrl
|
||||||
} as MiniAppReqCustomParams;
|
} as MiniAppReqCustomParams;
|
||||||
if (payload.type) {
|
if ('type' in payload) {
|
||||||
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
|
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
|
||||||
} else {
|
} else {
|
||||||
const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload;
|
const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload;
|
||||||
|
@@ -1,34 +1,28 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
properties: {
|
start: Type.Union([Type.Number(), Type.String()], { default: 0 }),
|
||||||
user_id: { type: ['number', 'string'] },
|
count: Type.Union([Type.Number(), Type.String()], { default: 10 }),
|
||||||
start: { type: ['number', 'string'] },
|
type: Type.Union([Type.Number(), Type.String()], { default: 2 }),
|
||||||
count: { type: ['number', 'string'] },
|
});
|
||||||
type: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetProfileLike extends OneBotAction<Payload, any> {
|
export class GetProfileLike extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GetProfileLike;
|
actionName = ActionName.GetProfileLike;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const start = payload.start ? Number(payload.start) : 0;
|
|
||||||
const count = payload.count ? Number(payload.count) : 10;
|
|
||||||
const type = payload.count ? Number(payload.count) : 2;
|
|
||||||
const user_uid =
|
const user_uid =
|
||||||
this.core.selfInfo.uin === payload.user_id || !payload.user_id ?
|
this.core.selfInfo.uin === payload.user_id || !payload.user_id ?
|
||||||
this.core.selfInfo.uid :
|
this.core.selfInfo.uid :
|
||||||
await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
const ret = await this.core.apis.UserApi.getProfileLike(user_uid ?? this.core.selfInfo.uid, start, count, type);
|
const ret = await this.core.apis.UserApi.getProfileLike(user_uid ?? this.core.selfInfo.uid, +payload.start, +payload.count, +payload.type);
|
||||||
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
||||||
for (const item of listdata) {
|
for (const item of listdata) {
|
||||||
item.uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(item.uid)) || '');
|
item.uin = +((await this.core.apis.UserApi.getUinByUidV2(item.uid)) ?? '');
|
||||||
}
|
}
|
||||||
return ret.info.userLikeInfos[0].voteInfo;
|
return ret.info.userLikeInfos[0].voteInfo;
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
|
|
||||||
|
export class GetRkey extends GetPacketStatusDepends<void, Array<any>> {
|
||||||
export class GetRkey extends GetPacketStatusDepends<null, Array<any>> {
|
|
||||||
actionName = ActionName.GetRkey;
|
actionName = ActionName.GetRkey;
|
||||||
|
|
||||||
async _handle() {
|
async _handle() {
|
||||||
|
@@ -4,7 +4,7 @@ import { ActionName } from '@/onebot/action/router';
|
|||||||
export class GetRobotUinRange extends OneBotAction<void, Array<any>> {
|
export class GetRobotUinRange extends OneBotAction<void, Array<any>> {
|
||||||
actionName = ActionName.GetRobotUinRange;
|
actionName = ActionName.GetRobotUinRange;
|
||||||
|
|
||||||
async _handle(payload: void) {
|
async _handle() {
|
||||||
return await this.core.apis.UserApi.getRobotUinRange();
|
return await this.core.apis.UserApi.getRobotUinRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
// no_cache get时传字符串
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
const SchemaData = Type.Object({
|
||||||
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetUserStatus extends GetPacketStatusDepends<Payload, { status: number; ext_status: number; } | undefined> {
|
export class GetUserStatus extends GetPacketStatusDepends<Payload, { status: number; ext_status: number; } | undefined> {
|
||||||
actionName = ActionName.GetUserStatus;
|
actionName = ActionName.GetUserStatus;
|
||||||
|
@@ -1,25 +1,21 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
import { checkFileExist, uri2local } from '@/common/file';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
image: Type.String(),
|
||||||
properties: {
|
});
|
||||||
image: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['image'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class OCRImage extends OneBotAction<Payload, any> {
|
export class OCRImage extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.OCRImage;
|
actionName = ActionName.OCRImage;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
@@ -29,12 +25,12 @@ export class OCRImage extends OneBotAction<Payload, any> {
|
|||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error(`OCR ${payload.file}失败`);
|
throw new Error(`OCR ${payload.image}失败`);
|
||||||
}
|
}
|
||||||
return ret.result;
|
return ret.result;
|
||||||
}
|
}
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
throw new Error(`OCR ${payload.file}失败,文件可能不存在`);
|
throw new Error(`OCR ${payload.image}失败,文件可能不存在`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { GetPacketStatusDepends } from '@/onebot/action/packet/GetPacketStatus';
|
import { GetPacketStatusDepends } from '@/onebot/action/packet/GetPacketStatus';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['string', 'number'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> {
|
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> {
|
||||||
actionName = ActionName.SetGroupSign;
|
actionName = ActionName.SetGroupSign;
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType } from '@/core';
|
import { ChatType } from '@/core';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
event_type: Type.Number(),
|
||||||
event_type: { type: 'number' },
|
});
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['event_type', 'user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetInputStatus extends OneBotAction<Payload, any> {
|
export class SetInputStatus extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetInputStatus;
|
actionName = ActionName.SetInputStatus;
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
longNick: Type.String(),
|
||||||
properties: {
|
});
|
||||||
longNick: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['longNick'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetLongNick extends OneBotAction<Payload, any> {
|
export class SetLongNick extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetLongNick;
|
actionName = ActionName.SetLongNick;
|
||||||
|
@@ -1,19 +1,14 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
// 设置在线状态
|
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
status: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
ext_status: Type.Union([Type.Number(), Type.String()]),
|
||||||
status: { type: ['number', 'string'] },
|
battery_status: Type.Union([Type.Number(), Type.String()]),
|
||||||
ext_status: { type: ['number', 'string'] },
|
});
|
||||||
battery_status: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['status', 'ext_status', 'battery_status'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetOnlineStatus extends OneBotAction<Payload, null> {
|
export class SetOnlineStatus extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.SetOnlineStatus;
|
actionName = ActionName.SetOnlineStatus;
|
||||||
@@ -21,9 +16,9 @@ export class SetOnlineStatus extends OneBotAction<Payload, null> {
|
|||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const ret = await this.core.apis.UserApi.setSelfOnlineStatus(
|
const ret = await this.core.apis.UserApi.setSelfOnlineStatus(
|
||||||
parseInt(payload.status.toString()),
|
+payload.status,
|
||||||
parseInt(payload.ext_status.toString()),
|
+payload.ext_status,
|
||||||
parseInt(payload.battery_status.toString()),
|
+payload.battery_status,
|
||||||
);
|
);
|
||||||
if (ret.result !== 0) {
|
if (ret.result !== 0) {
|
||||||
throw new Error('设置在线状态失败');
|
throw new Error('设置在线状态失败');
|
||||||
|
@@ -1,39 +1,27 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import * as fs from 'node:fs';
|
import fs from 'node:fs/promises';
|
||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
interface Payload {
|
const SchemaData = Type.Object({
|
||||||
file: string;
|
file: Type.String(),
|
||||||
}
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class SetAvatar extends OneBotAction<Payload, null> {
|
export default class SetAvatar extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.SetQQAvatar;
|
actionName = ActionName.SetQQAvatar;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
// 用不着复杂检测
|
|
||||||
protected async check(payload: Payload): Promise<BaseCheckResult> {
|
|
||||||
if (!payload.file || typeof payload.file != 'string') {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: 'file字段不能为空或者类型错误',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
valid: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileExist(path, 5000);// 避免崩溃
|
await checkFileExist(path, 5000);// 避免崩溃
|
||||||
const ret = await this.core.apis.UserApi.setQQAvatar(path);
|
const ret = await this.core.apis.UserApi.setQQAvatar(path);
|
||||||
fs.unlink(path, () => {
|
fs.unlink(path).catch(() => { });
|
||||||
});
|
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
@@ -44,8 +32,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
|
|||||||
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
|
|
||||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@@ -1,17 +1,14 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
const SchemaData = {
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
special_title: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'user_id', 'special_title'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
const SchemaData = Type.Object({
|
||||||
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
special_title: Type.String(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetSpecialTittle extends GetPacketStatusDepends<Payload, any> {
|
export class SetSpecialTittle extends GetPacketStatusDepends<Payload, any> {
|
||||||
actionName = ActionName.SetSpecialTittle;
|
actionName = ActionName.SetSpecialTittle;
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
properties: {
|
group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
user_id: { type: 'string' },
|
phoneNumber: Type.String({ default: '' }),
|
||||||
group_id: { type: 'string' },
|
});
|
||||||
phoneNumber: { type: 'string' },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SharePeer extends OneBotAction<Payload, any> {
|
export class SharePeer extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SharePeer;
|
actionName = ActionName.SharePeer;
|
||||||
@@ -20,28 +16,24 @@ export class SharePeer extends OneBotAction<Payload, any> {
|
|||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
if (payload.group_id) {
|
if (payload.group_id) {
|
||||||
return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id);
|
return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id.toString());
|
||||||
} else if (payload.user_id) {
|
} else if (payload.user_id) {
|
||||||
return await this.core.apis.UserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || '');
|
return await this.core.apis.UserApi.getBuddyRecommendContactArkJson(payload.user_id.toString(), payload.phoneNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SchemaDataGroupEx = {
|
const SchemaDataGroupEx = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>;
|
type PayloadGroupEx = Static<typeof SchemaDataGroupEx>;
|
||||||
|
|
||||||
export class ShareGroupEx extends OneBotAction<PayloadGroupEx, any> {
|
export class ShareGroupEx extends OneBotAction<PayloadGroupEx, any> {
|
||||||
actionName = ActionName.ShareGroupEx;
|
actionName = ActionName.ShareGroupEx;
|
||||||
payloadSchema = SchemaDataGroupEx;
|
payloadSchema = SchemaDataGroupEx;
|
||||||
|
|
||||||
async _handle(payload: PayloadGroupEx) {
|
async _handle(payload: PayloadGroupEx) {
|
||||||
return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id);
|
return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
words: Type.Array(Type.String()),
|
||||||
properties: {
|
});
|
||||||
words: {
|
|
||||||
type: 'array',
|
|
||||||
items: { type: 'string' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ['words'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class TranslateEnWordToZn extends OneBotAction<Payload, Array<any> | null> {
|
export class TranslateEnWordToZn extends OneBotAction<Payload, Array<any> | null> {
|
||||||
actionName = ActionName.TranslateEnWordToZn;
|
actionName = ActionName.TranslateEnWordToZn;
|
||||||
|
@@ -2,12 +2,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
|
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
// interface GetFilePayload {
|
|
||||||
// file: string; // 文件名或者fileUuid
|
|
||||||
// }
|
|
||||||
|
|
||||||
export interface GetFileResponse {
|
export interface GetFileResponse {
|
||||||
file?: string; // path
|
file?: string; // path
|
||||||
@@ -16,19 +12,14 @@ export interface GetFileResponse {
|
|||||||
file_name?: string;
|
file_name?: string;
|
||||||
base64?: string;
|
base64?: string;
|
||||||
}
|
}
|
||||||
const GetFileBase_PayloadSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
file: { type: 'string' },
|
|
||||||
file_id: { type: 'string' }
|
|
||||||
},
|
|
||||||
oneOf: [
|
|
||||||
{ required: ['file'] },
|
|
||||||
{ required: ['file_id'] }
|
|
||||||
]
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
export type GetFilePayload = FromSchema<typeof GetFileBase_PayloadSchema>;
|
const GetFileBase_PayloadSchema = Type.Object({
|
||||||
|
file: Type.Optional(Type.String()),
|
||||||
|
file_id: Type.Optional(Type.String())
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export type GetFilePayload = Static<typeof GetFileBase_PayloadSchema>;
|
||||||
|
|
||||||
export class GetFileBase extends OneBotAction<GetFilePayload, GetFileResponse> {
|
export class GetFileBase extends OneBotAction<GetFilePayload, GetFileResponse> {
|
||||||
payloadSchema = GetFileBase_PayloadSchema;
|
payloadSchema = GetFileBase_PayloadSchema;
|
||||||
@@ -50,12 +41,12 @@ export class GetFileBase extends OneBotAction<GetFilePayload, GetFileResponse> {
|
|||||||
let url = '';
|
let url = '';
|
||||||
if (mixElement?.picElement && rawMessage) {
|
if (mixElement?.picElement && rawMessage) {
|
||||||
const tempData =
|
const tempData =
|
||||||
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement) as OB11MessageImage | undefined;
|
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageImage | undefined;
|
||||||
url = tempData?.data.url ?? '';
|
url = tempData?.data.url ?? '';
|
||||||
}
|
}
|
||||||
if (mixElement?.videoElement && rawMessage) {
|
if (mixElement?.videoElement && rawMessage) {
|
||||||
const tempData =
|
const tempData =
|
||||||
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement) as OB11MessageVideo | undefined;
|
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageVideo | undefined;
|
||||||
url = tempData?.data.url ?? '';
|
url = tempData?.data.url ?? '';
|
||||||
}
|
}
|
||||||
const res: GetFileResponse = {
|
const res: GetFileResponse = {
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { FileNapCatOneBotUUID } from "@/common/helper";
|
import { FileNapCatOneBotUUID } from "@/common/helper";
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
file_id: Type.String(),
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
file_id: { type: ['string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'file_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
interface GetGroupFileUrlResponse {
|
interface GetGroupFileUrlResponse {
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@@ -1,22 +1,18 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
folder_name: Type.String(),
|
||||||
group_id: { type: ['string', 'number'] },
|
});
|
||||||
folder_name: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'folder_name'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class CreateGroupFileFolder extends OneBotAction<Payload, any> {
|
export class CreateGroupFileFolder extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder;
|
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
return (await this.core.apis.GroupApi.CreatGroupFileFolder(payload.group_id.toString(), payload.folder_name)).resultWithGroupItem;
|
return (await this.core.apis.GroupApi.creatGroupFileFolder(payload.group_id.toString(), payload.folder_name)).resultWithGroupItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,15 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
file_id: Type.String(),
|
||||||
group_id: { type: ['string', 'number'] },
|
});
|
||||||
file_id: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'file_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class DeleteGroupFile extends OneBotAction<Payload, any> {
|
export class DeleteGroupFile extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GOCQHTTP_DeleteGroupFile;
|
actionName = ActionName.GOCQHTTP_DeleteGroupFile;
|
||||||
@@ -20,6 +17,6 @@ export class DeleteGroupFile extends OneBotAction<Payload, any> {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id);
|
const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id);
|
||||||
if (!data) throw new Error('Invalid file_id');
|
if (!data) throw new Error('Invalid file_id');
|
||||||
return await this.core.apis.GroupApi.DelGroupFile(payload.group_id.toString(), [data.fileId]);
|
return await this.core.apis.GroupApi.delGroupFile(payload.group_id.toString(), [data.fileId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +1,20 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
folder_id: Type.Optional(Type.String()),
|
||||||
group_id: { type: ['string', 'number'] },
|
folder: Type.Optional(Type.String()),
|
||||||
folder_id: { type: 'string' },
|
});
|
||||||
folder: { type: 'string' }
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class DeleteGroupFileFolder extends OneBotAction<Payload, any> {
|
export class DeleteGroupFileFolder extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder;
|
actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
return (await this.core.apis.GroupApi.DelGroupFileFolder(
|
return (await this.core.apis.GroupApi.delGroupFileFolder(
|
||||||
payload.group_id.toString(), payload.folder ?? payload.folder_id ?? '')).groupFileCommonResult;
|
payload.group_id.toString(), payload.folder ?? payload.folder_id ?? '')).groupFileCommonResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,29 +4,20 @@ import fs from 'fs';
|
|||||||
import { join as joinPath } from 'node:path';
|
import { join as joinPath } from 'node:path';
|
||||||
import { calculateFileMD5, httpDownload } from '@/common/file';
|
import { calculateFileMD5, httpDownload } from '@/common/file';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
interface FileResponse {
|
interface FileResponse {
|
||||||
file: string;
|
file: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
url: Type.Optional(Type.String()),
|
||||||
properties: {
|
base64: Type.Optional(Type.String()),
|
||||||
thread_count: { type: ['number', 'string'] },
|
name: Type.Optional(Type.String()),
|
||||||
url: { type: 'string' },
|
headers: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())])),
|
||||||
base64: { type: 'string' },
|
});
|
||||||
name: { type: 'string' },
|
|
||||||
headers: {
|
|
||||||
type: ['string', 'array'],
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class GoCQHTTPDownloadFile extends OneBotAction<Payload, FileResponse> {
|
export default class GoCQHTTPDownloadFile extends OneBotAction<Payload, FileResponse> {
|
||||||
actionName = ActionName.GoCQHTTP_DownloadFile;
|
actionName = ActionName.GoCQHTTP_DownloadFile;
|
||||||
|
@@ -1,20 +1,15 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageForward, OB11MessageNodePlain as OB11MessageNode } from '@/onebot';
|
import { OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageForward, OB11MessageNodePlain as OB11MessageNode } from '@/onebot';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
message_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
|
id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
message_id: { type: 'string' },
|
|
||||||
id: { type: 'string' },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
|
export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_GetForwardMsg;
|
actionName = ActionName.GoCQHTTP_GetForwardMsg;
|
||||||
@@ -60,7 +55,7 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
|
|||||||
throw new Error('message_id is required');
|
throw new Error('message_id is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
|
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId.toString());
|
||||||
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
|
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
|
||||||
if (!rootMsg) {
|
if (!rootMsg) {
|
||||||
throw new Error('msg not found');
|
throw new Error('msg not found');
|
||||||
|
@@ -2,26 +2,22 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { OB11Message } from '@/onebot';
|
import { OB11Message } from '@/onebot';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType } from '@/core/types';
|
import { ChatType } from '@/core/types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
messages: OB11Message[];
|
messages: OB11Message[];
|
||||||
}
|
}
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
message_seq: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
|
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
|
||||||
|
reverseOrder: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
|
||||||
|
});
|
||||||
|
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
message_seq: { type: ['number', 'string'] },
|
|
||||||
count: { type: ['number', 'string'] },
|
|
||||||
reverseOrder: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class GetFriendMsgHistory extends OneBotAction<Payload, Response> {
|
export default class GetFriendMsgHistory extends OneBotAction<Payload, Response> {
|
||||||
actionName = ActionName.GetFriendMsgHistory;
|
actionName = ActionName.GetFriendMsgHistory;
|
||||||
@@ -30,7 +26,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
|
|||||||
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
||||||
//处理参数
|
//处理参数
|
||||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
const MsgCount = +(payload.count ?? 20);
|
|
||||||
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
||||||
if (!uid) throw new Error(`记录${payload.user_id}不存在`);
|
if (!uid) throw new Error(`记录${payload.user_id}不存在`);
|
||||||
const friend = await this.core.apis.FriendApi.isBuddy(uid);
|
const friend = await this.core.apis.FriendApi.isBuddy(uid);
|
||||||
@@ -38,7 +34,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
|
|||||||
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
||||||
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||||
const msgList = hasMessageSeq ?
|
const msgList = hasMessageSeq ?
|
||||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, +payload.count)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, +payload.count)).msgList;
|
||||||
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
||||||
//翻转消息
|
//翻转消息
|
||||||
if (isReverseOrder) msgList.reverse();
|
if (isReverseOrder) msgList.reverse();
|
||||||
|
@@ -1,15 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()])
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['number', 'string'] }
|
|
||||||
},
|
type Payload = Static<typeof SchemaData>;
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GoCQHTTPGetGroupAtAllRemain extends OneBotAction<Payload, any> {
|
export class GoCQHTTPGetGroupAtAllRemain extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain;
|
actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain;
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()])
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['string', 'number'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupFileSystemInfo extends OneBotAction<Payload, {
|
export class GetGroupFileSystemInfo extends OneBotAction<Payload, {
|
||||||
file_count: number,
|
file_count: number,
|
||||||
|
@@ -1,20 +1,17 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
folder_id: Type.Optional(Type.String()),
|
||||||
group_id: { type: ['string', 'number'] },
|
folder: Type.Optional(Type.String()),
|
||||||
folder_id: { type: 'string' },
|
file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }),
|
||||||
folder: { type: 'string' },
|
});
|
||||||
file_count: { type: ['string', 'number'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupFilesByFolder extends OneBotAction<any, any> {
|
export class GetGroupFilesByFolder extends OneBotAction<any, any> {
|
||||||
actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder;
|
actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder;
|
||||||
@@ -23,7 +20,7 @@ export class GetGroupFilesByFolder extends OneBotAction<any, any> {
|
|||||||
|
|
||||||
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
||||||
sortType: 1,
|
sortType: 1,
|
||||||
fileCount: +(payload.file_count ?? 50),
|
fileCount: +payload.file_count,
|
||||||
startIndex: 0,
|
startIndex: 0,
|
||||||
sortOrder: 2,
|
sortOrder: 2,
|
||||||
showOnlinedocFolder: 0,
|
showOnlinedocFolder: 0,
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { WebHonorType } from '@/core/types';
|
import { WebHonorType } from '@/core/types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
type: Type.Optional(Type.Enum(WebHonorType))
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
type: { enum: [WebHonorType.ALL, WebHonorType.EMOTION, WebHonorType.LEGEND, WebHonorType.PERFORMER, WebHonorType.STRONG_NEWBIE, WebHonorType.TALKATIVE] },
|
|
||||||
},
|
type Payload = Static<typeof SchemaData>;
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
// enum是不是有点抽象
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GetGroupHonorInfo extends OneBotAction<Payload, Array<any>> {
|
export class GetGroupHonorInfo extends OneBotAction<Payload, Array<any>> {
|
||||||
actionName = ActionName.GetGroupHonorInfo;
|
actionName = ActionName.GetGroupHonorInfo;
|
||||||
|
@@ -2,26 +2,24 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { OB11Message } from '@/onebot';
|
import { OB11Message } from '@/onebot';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType, Peer } from '@/core/types';
|
import { ChatType, Peer } from '@/core/types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
messages: OB11Message[];
|
messages: OB11Message[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
message_seq: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
group_id: { type: ['number', 'string'] },
|
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
|
||||||
message_seq: { type: ['number', 'string'] },
|
reverseOrder: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
|
||||||
count: { type: ['number', 'string'] },
|
});
|
||||||
reverseOrder: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
type Payload = Static<typeof SchemaData>;
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Response> {
|
export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Response> {
|
||||||
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
|
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
|
||||||
@@ -30,13 +28,12 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
|
|||||||
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
async _handle(payload: Payload, adapter: string): Promise<Response> {
|
||||||
//处理参数
|
//处理参数
|
||||||
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
||||||
const MsgCount = +(payload.count ?? 20);
|
|
||||||
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
|
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
|
||||||
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
||||||
//拉取消息
|
//拉取消息
|
||||||
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||||
const msgList = hasMessageSeq ?
|
const msgList = hasMessageSeq ?
|
||||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, +payload.count)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, +payload.count)).msgList;
|
||||||
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
||||||
//翻转消息
|
//翻转消息
|
||||||
if (isReverseOrder) msgList.reverse();
|
if (isReverseOrder) msgList.reverse();
|
||||||
|
@@ -1,19 +1,16 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
|
import { OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
|
||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }),
|
||||||
group_id: { type: ['string', 'number'] },
|
});
|
||||||
file_count: { type: ['string', 'number'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupRootFiles extends OneBotAction<Payload, {
|
export class GetGroupRootFiles extends OneBotAction<Payload, {
|
||||||
files: OB11GroupFile[],
|
files: OB11GroupFile[],
|
||||||
@@ -24,7 +21,7 @@ export class GetGroupRootFiles extends OneBotAction<Payload, {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
||||||
sortType: 1,
|
sortType: 1,
|
||||||
fileCount: +(payload.file_count ?? 50),
|
fileCount: +payload.file_count,
|
||||||
startIndex: 0,
|
startIndex: 0,
|
||||||
sortOrder: 2,
|
sortOrder: 2,
|
||||||
showOnlinedocFolder: 0,
|
showOnlinedocFolder: 0,
|
||||||
|
@@ -1,15 +1,7 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { sleep } from '@/common/helper';
|
import { sleep } from '@/common/helper';
|
||||||
|
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
no_cache: { type: 'boolean' },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
export class GetOnlineClient extends OneBotAction<void, Array<any>> {
|
export class GetOnlineClient extends OneBotAction<void, Array<any>> {
|
||||||
actionName = ActionName.GetOnlineClient;
|
actionName = ActionName.GetOnlineClient;
|
||||||
|
|
||||||
|
@@ -2,18 +2,14 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { OB11User, OB11UserSex } from '@/onebot';
|
import { OB11User, OB11UserSex } from '@/onebot';
|
||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { calcQQLevel } from '@/common/helper';
|
import { calcQQLevel } from '@/common/helper';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class GoCQHTTPGetStrangerInfo extends OneBotAction<Payload, OB11User> {
|
export default class GoCQHTTPGetStrangerInfo extends OneBotAction<Payload, OB11User> {
|
||||||
actionName = ActionName.GoCQHTTP_GetStrangerInfo;
|
actionName = ActionName.GoCQHTTP_GetStrangerInfo;
|
||||||
|
@@ -1,15 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
url: Type.String(),
|
||||||
properties: {
|
});
|
||||||
url: { type: 'string' },
|
|
||||||
},
|
type Payload = Static<typeof SchemaData>;
|
||||||
required: ['url'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GoCQHTTPCheckUrlSafely extends OneBotAction<Payload, any> {
|
export class GoCQHTTPCheckUrlSafely extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_CheckUrlSafely;
|
actionName = ActionName.GoCQHTTP_CheckUrlSafely;
|
||||||
|
@@ -1,22 +1,15 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
friend_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
|
||||||
properties: {
|
user_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
|
||||||
friend_id: { type: ['string', 'number'] },
|
temp_block: Type.Optional(Type.Boolean()),
|
||||||
user_id: { type: ['string', 'number'] },
|
temp_both_del: Type.Optional(Type.Boolean()),
|
||||||
temp_block: { type: 'boolean' },
|
});
|
||||||
temp_both_del: { type: 'boolean' },
|
|
||||||
},
|
|
||||||
oneOf: [
|
|
||||||
{ required: ['friend_id'] },
|
|
||||||
{ required: ['user_id'] },
|
|
||||||
],
|
|
||||||
|
|
||||||
} as const satisfies JSONSchema;
|
type Payload = Static<typeof SchemaData>;
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GoCQHTTPDeleteFriend extends OneBotAction<Payload, any> {
|
export class GoCQHTTPDeleteFriend extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_DeleteFriend;
|
actionName = ActionName.GoCQHTTP_DeleteFriend;
|
||||||
|
@@ -1,14 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
model: Type.String(),
|
||||||
properties: {
|
});
|
||||||
model: { type: 'string' },
|
|
||||||
}
|
type Payload = Static<typeof SchemaData>;
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class GoCQHTTPGetModelShow extends OneBotAction<Payload, any> {
|
export class GoCQHTTPGetModelShow extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_GetModelShow;
|
actionName = ActionName.GoCQHTTP_GetModelShow;
|
||||||
|
@@ -1,19 +1,10 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
|
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
//兼容性代码
|
//兼容性代码
|
||||||
export class GoCQHTTPSetModelShow extends OneBotAction<Payload, any> {
|
export class GoCQHTTPSetModelShow extends OneBotAction<void, any> {
|
||||||
actionName = ActionName.GoCQHTTP_SetModelShow;
|
actionName = ActionName.GoCQHTTP_SetModelShow;
|
||||||
payloadSchema = SchemaData;
|
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: void) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@ export class GoCQHTTPHandleQuickAction extends OneBotAction<Payload, null> {
|
|||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
this.obContext.apis.QuickActionApi
|
this.obContext.apis.QuickActionApi
|
||||||
.handleQuickOperation(payload.context, payload.operation)
|
.handleQuickOperation(payload.context, payload.operation)
|
||||||
.catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
.catch(e => this.core.context.logger.logError(e));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,21 @@
|
|||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { unlink } from 'node:fs';
|
import { unlink } from 'node:fs/promises';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
content: Type.String(),
|
||||||
group_id: { type: ['number', 'string'] },
|
image: Type.Optional(Type.String()),
|
||||||
content: { type: 'string' },
|
pinned: Type.Union([Type.Number(), Type.String()], { default: 0 }),
|
||||||
image: { type: 'string' },
|
type: Type.Union([Type.Number(), Type.String()], { default: 1 }),
|
||||||
pinned: { type: ['number', 'string'] },
|
confirm_required: Type.Union([Type.Number(), Type.String()], { default: 1 }),
|
||||||
type: { type: ['number', 'string'] },
|
is_show_edit_card: Type.Union([Type.Number(), Type.String()], { default: 0 }),
|
||||||
confirm_required: { type: ['number', 'string'] },
|
tip_window_type: Type.Union([Type.Number(), Type.String()], { default: 0 })
|
||||||
is_show_edit_card: { type: ['number', 'string'] },
|
});
|
||||||
tip_window_type: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'content'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SendGroupNotice extends OneBotAction<Payload, null> {
|
export class SendGroupNotice extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.GoCQHTTP_SendGroupNotice;
|
actionName = ActionName.GoCQHTTP_SendGroupNotice;
|
||||||
@@ -32,7 +28,7 @@ export class SendGroupNotice extends OneBotAction<Payload, null> {
|
|||||||
const {
|
const {
|
||||||
path,
|
path,
|
||||||
success,
|
success,
|
||||||
} = (await uri2local(this.core.NapCatTempPath, payload.image));
|
} = (await uriToLocalFile(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
@@ -45,26 +41,18 @@ export class SendGroupNotice extends OneBotAction<Payload, null> {
|
|||||||
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(path, () => {
|
unlink(path).catch(() => { });
|
||||||
});
|
|
||||||
|
|
||||||
UploadImage = ImageUploadResult.picInfo;
|
UploadImage = ImageUploadResult.picInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noticeType = +(payload.type ?? 1);
|
|
||||||
const noticePinned = +(payload.pinned ?? 0);
|
|
||||||
|
|
||||||
const noticeShowEditCard = +(payload.is_show_edit_card ?? 0);
|
|
||||||
const noticeTipWindowType = +(payload.tip_window_type ?? 0);
|
|
||||||
const noticeConfirmRequired = +(payload.confirm_required ?? 1);
|
|
||||||
const publishGroupBulletinResult = await this.core.apis.WebApi.setGroupNotice(
|
const publishGroupBulletinResult = await this.core.apis.WebApi.setGroupNotice(
|
||||||
payload.group_id.toString(),
|
payload.group_id.toString(),
|
||||||
payload.content,
|
payload.content,
|
||||||
noticePinned,
|
+payload.pinned,
|
||||||
noticeType,
|
+payload.type,
|
||||||
noticeShowEditCard,
|
+payload.is_show_edit_card,
|
||||||
noticeTipWindowType,
|
+payload.tip_window_type,
|
||||||
noticeConfirmRequired,
|
+payload.confirm_required,
|
||||||
UploadImage?.id,
|
UploadImage?.id,
|
||||||
UploadImage?.width,
|
UploadImage?.width,
|
||||||
UploadImage?.height
|
UploadImage?.height
|
||||||
|
@@ -1,38 +1,28 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import * as fs from 'node:fs';
|
import { checkFileExistV2, uriToLocalFile } from '@/common/file';
|
||||||
import { checkFileExistV2, uri2local } from '@/common/file';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
file: Type.String(),
|
||||||
|
group_id: Type.Union([Type.Number(), Type.String()])
|
||||||
|
});
|
||||||
|
|
||||||
interface Payload {
|
type Payload = Static<typeof SchemaData>;
|
||||||
file: string,
|
|
||||||
group_id: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetGroupPortrait;
|
actionName = ActionName.SetGroupPortrait;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
// 用不着复杂检测
|
|
||||||
protected async check(payload: Payload): Promise<BaseCheckResult> {
|
|
||||||
if (!payload.file || typeof payload.file != 'string' || !payload.group_id || typeof payload.group_id != 'number') {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: 'file和group_id字段不能为空或者类型错误',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
valid: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<any> {
|
async _handle(payload: Payload): Promise<any> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
@@ -43,7 +33,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path).catch(() => { });
|
||||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
nickname: Type.String(),
|
||||||
properties: {
|
personal_note: Type.Optional(Type.String()),
|
||||||
nickname: { type: 'string' },
|
sex: Type.Optional(Type.Union([Type.Number(), Type.String()])), // 传Sex值?建议传0
|
||||||
personal_note: { type: 'string' },
|
});
|
||||||
sex: { type: ['number', 'string'] },//传Sex值?建议传0
|
|
||||||
},
|
|
||||||
required: ['nickname'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetQQProfile extends OneBotAction<Payload, any> {
|
export class SetQQProfile extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetQQProfile;
|
actionName = ActionName.SetQQProfile;
|
||||||
|
@@ -2,23 +2,19 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType, Peer } from '@/core/types';
|
import { ChatType, Peer } from '@/core/types';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { uri2local } from '@/common/file';
|
import { uriToLocalFile } from '@/common/file';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { SendMessageContext } from '@/onebot/api';
|
||||||
import { MessageContext } from '@/onebot/api';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
file: Type.String(),
|
||||||
group_id: { type: ['number', 'string'] },
|
name: Type.String(),
|
||||||
file: { type: 'string' },
|
folder: Type.Optional(Type.String()),
|
||||||
name: { type: 'string' },
|
folder_id: Type.Optional(Type.String()),//临时扩展
|
||||||
folder: { type: 'string' },
|
});
|
||||||
folder_id: { type: 'string' },//临时扩展
|
|
||||||
},
|
|
||||||
required: ['group_id', 'file', 'name'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null> {
|
export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.GoCQHTTP_UploadGroupFile;
|
actionName = ActionName.GoCQHTTP_UploadGroupFile;
|
||||||
@@ -29,7 +25,7 @@ export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null>
|
|||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
file = `file://${file}`;
|
file = `file://${file}`;
|
||||||
}
|
}
|
||||||
const downloadResult = await uri2local(this.core.NapCatTempPath, file);
|
const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, file);
|
||||||
const peer: Peer = {
|
const peer: Peer = {
|
||||||
chatType: ChatType.KCHATTYPEGROUP,
|
chatType: ChatType.KCHATTYPEGROUP,
|
||||||
peerUid: payload.group_id.toString(),
|
peerUid: payload.group_id.toString(),
|
||||||
@@ -37,7 +33,7 @@ export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null>
|
|||||||
if (!downloadResult.success) {
|
if (!downloadResult.success) {
|
||||||
throw new Error(downloadResult.errMsg);
|
throw new Error(downloadResult.errMsg);
|
||||||
}
|
}
|
||||||
const msgContext: MessageContext = {
|
const msgContext: SendMessageContext = {
|
||||||
peer: peer,
|
peer: peer,
|
||||||
deleteAfterSentFiles: []
|
deleteAfterSentFiles: []
|
||||||
};
|
};
|
||||||
|
@@ -2,22 +2,18 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType, Peer, SendFileElement } from '@/core/types';
|
import { ChatType, Peer, SendFileElement } from '@/core/types';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { uri2local } from '@/common/file';
|
import { uriToLocalFile } from '@/common/file';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { SendMessageContext } from '@/onebot/api';
|
||||||
import { MessageContext } from '@/onebot/api';
|
|
||||||
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
|
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
file: Type.String(),
|
||||||
user_id: { type: ['number', 'string'] },
|
name: Type.String(),
|
||||||
file: { type: 'string' },
|
});
|
||||||
name: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['user_id', 'file', 'name'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, null> {
|
export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.GOCQHTTP_UploadPrivateFile;
|
actionName = ActionName.GOCQHTTP_UploadPrivateFile;
|
||||||
@@ -40,12 +36,12 @@ export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, nul
|
|||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
file = `file://${file}`;
|
file = `file://${file}`;
|
||||||
}
|
}
|
||||||
const downloadResult = await uri2local(this.core.NapCatTempPath, file);
|
const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, file);
|
||||||
if (!downloadResult.success) {
|
if (!downloadResult.success) {
|
||||||
throw new Error(downloadResult.errMsg);
|
throw new Error(downloadResult.errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const msgContext: MessageContext = {
|
const msgContext: SendMessageContext = {
|
||||||
peer: await createContext(this.core, {
|
peer: await createContext(this.core, {
|
||||||
user_id: payload.user_id.toString(),
|
user_id: payload.user_id.toString(),
|
||||||
group_id: undefined,
|
group_id: undefined,
|
||||||
|
@@ -1,17 +1,13 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
message_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
message_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['message_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class DelEssenceMsg extends OneBotAction<Payload, any> {
|
export default class DelEssenceMsg extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.DelEssenceMsg;
|
actionName = ActionName.DelEssenceMsg;
|
||||||
|
@@ -1,18 +1,13 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
notice_id: Type.String()
|
||||||
|
});
|
||||||
|
|
||||||
const SchemaData = {
|
type Payload = Static<typeof SchemaData>;
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
notice_id: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'notice_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class DelGroupNotice extends OneBotAction<Payload, any> {
|
export class DelGroupNotice extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.DelGroupNotice;
|
actionName = ActionName.DelGroupNotice;
|
||||||
|
@@ -1,19 +1,15 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
character: Type.String(),
|
||||||
properties: {
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
character: { type: ['string'] },
|
text: Type.String(),
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
text: { type: 'string' },
|
|
||||||
},
|
|
||||||
required: ['character', 'group_id', 'text'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetAiRecord extends GetPacketStatusDepends<Payload, string> {
|
export class GetAiRecord extends GetPacketStatusDepends<Payload, string> {
|
||||||
actionName = ActionName.GetAiRecord;
|
actionName = ActionName.GetAiRecord;
|
||||||
|
@@ -1,20 +1,16 @@
|
|||||||
import { ChatType, Peer } from '@/core';
|
import { ChatType, Peer } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { AdapterConfigWrap } from '@/onebot/config/config';
|
import { AdapterConfigWrap } from '@/onebot/config/config';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['number', 'string'] }
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupEssence extends OneBotAction<Payload, any> {
|
export class GetGroupEssence extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GoCQHTTP_GetEssenceMsg;
|
actionName = ActionName.GoCQHTTP_GetEssenceMsg;
|
||||||
|
@@ -1,37 +1,44 @@
|
|||||||
import { GroupNotifyMsgStatus } from '@/core';
|
import { GroupNotifyMsgStatus } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Notify } from '@/onebot/types';
|
||||||
|
|
||||||
const SchemaData = {
|
interface RetData {
|
||||||
type: 'object',
|
InvitedRequest: Notify[];
|
||||||
properties: {
|
join_requests: Notify[];
|
||||||
group_id: { type: ['number', 'string'] },
|
}
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
export class GetGroupIgnoredNotifies extends OneBotAction<void, RetData> {
|
||||||
|
|
||||||
export class GetGroupIgnoredNotifies extends OneBotAction<void, any> {
|
|
||||||
actionName = ActionName.GetGroupIgnoredNotifies;
|
actionName = ActionName.GetGroupIgnoredNotifies;
|
||||||
|
|
||||||
async _handle(payload: void) {
|
async _handle(): Promise<RetData> {
|
||||||
const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
|
const SingleScreenNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(false, 50);
|
||||||
const retData: any = {
|
const retData: RetData = { InvitedRequest: [], join_requests: [] };
|
||||||
join_requests: await Promise.all(
|
|
||||||
ignoredNotifies
|
const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => {
|
||||||
.filter(notify => notify.type === 7)
|
const invitorUin = SSNotify.user1?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||||
.map(async SSNotify => ({
|
const actorUin = SSNotify.user2?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||||
request_id: SSNotify.seq,
|
const commonData = {
|
||||||
requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
|
request_id: +SSNotify.seq,
|
||||||
requester_nick: SSNotify.user1?.nickName,
|
invitor_uin: invitorUin,
|
||||||
group_id: SSNotify.group?.groupCode,
|
invitor_nick: SSNotify.user1?.nickName,
|
||||||
group_name: SSNotify.group?.groupName,
|
group_id: +SSNotify.group?.groupCode,
|
||||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
message: SSNotify?.postscript,
|
||||||
actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
group_name: SSNotify.group?.groupName,
|
||||||
}))),
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
};
|
actor: actorUin,
|
||||||
|
requester_nick: SSNotify.user1?.nickName,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (SSNotify.type === 1) {
|
||||||
|
retData.InvitedRequest.push(commonData);
|
||||||
|
} else if (SSNotify.type === 7) {
|
||||||
|
retData.join_requests.push(commonData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(notifyPromises);
|
||||||
|
|
||||||
return retData;
|
return retData;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,17 +2,13 @@ import { OB11Group } from '@/onebot';
|
|||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
class GetGroupInfo extends OneBotAction<Payload, OB11Group> {
|
class GetGroupInfo extends OneBotAction<Payload, OB11Group> {
|
||||||
actionName = ActionName.GetGroupInfo;
|
actionName = ActionName.GetGroupInfo;
|
||||||
|
@@ -2,16 +2,13 @@ import { OB11Group } from '@/onebot';
|
|||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
// no_cache get时传字符串
|
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
no_cache: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
const SchemaData = Type.Object({
|
||||||
|
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
class GetGroupList extends OneBotAction<Payload, OB11Group[]> {
|
class GetGroupList extends OneBotAction<Payload, OB11Group[]> {
|
||||||
actionName = ActionName.GetGroupList;
|
actionName = ActionName.GetGroupList;
|
||||||
|
@@ -2,19 +2,15 @@ import { OB11GroupMember } from '@/onebot';
|
|||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
group_id: { type: ['number', 'string'] },
|
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
|
||||||
user_id: { type: ['number', 'string'] },
|
});
|
||||||
no_cache: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
|
class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
|
||||||
actionName = ActionName.GetGroupMemberInfo;
|
actionName = ActionName.GetGroupMemberInfo;
|
||||||
|
@@ -2,18 +2,14 @@ import { OB11GroupMember } from '@/onebot';
|
|||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
no_cache: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]> {
|
export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]> {
|
||||||
actionName = ActionName.GetGroupMemberList;
|
actionName = ActionName.GetGroupMemberList;
|
||||||
@@ -23,11 +19,14 @@ export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]>
|
|||||||
const groupIdStr = payload.group_id.toString();
|
const groupIdStr = payload.group_id.toString();
|
||||||
const noCache = payload.no_cache ? this.stringToBoolean(payload.no_cache) : false;
|
const noCache = payload.no_cache ? this.stringToBoolean(payload.no_cache) : false;
|
||||||
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
||||||
let groupMembers;
|
let groupMembers = memberCache.get(groupIdStr);
|
||||||
try {
|
if (noCache || !groupMembers) {
|
||||||
groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr, 3000, noCache);
|
this.core.apis.GroupApi.refreshGroupMemberCache(groupIdStr).then().catch();
|
||||||
} catch (error) {
|
//下次刷新
|
||||||
groupMembers = memberCache.get(groupIdStr) ?? await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr);
|
groupMembers = memberCache.get(groupIdStr);
|
||||||
|
if (!groupMembers) {
|
||||||
|
throw new Error(`Failed to get group member list for group ${groupIdStr}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const memberPromises = Array.from(groupMembers.values()).map(item =>
|
const memberPromises = Array.from(groupMembers.values()).map(item =>
|
||||||
OB11Construct.groupMember(groupIdStr, item)
|
OB11Construct.groupMember(groupIdStr, item)
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
import { WebApiGroupNoticeFeed } from '@/core';
|
import { WebApiGroupNoticeFeed } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
interface GroupNotice {
|
interface GroupNotice {
|
||||||
sender_id: number;
|
sender_id: number;
|
||||||
publish_time: number;
|
publish_time: number;
|
||||||
@@ -17,15 +16,11 @@ interface GroupNotice {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed;
|
type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed;
|
||||||
|
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GetGroupShutList extends OneBotAction<Payload, any> {
|
export class GetGroupShutList extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.GetGroupShutList;
|
actionName = ActionName.GetGroupShutList;
|
||||||
|
@@ -1,17 +1,13 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
// no_cache get时传字符串
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
group_id: { type: ['number', 'string'] },
|
|
||||||
user_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
const SchemaData = Type.Object({
|
||||||
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
|
export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
|
||||||
actionName = ActionName.GroupPoke;
|
actionName = ActionName.GroupPoke;
|
||||||
|
@@ -1,21 +1,18 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import { uri2local } from "@/common/file";
|
import { uriToLocalFile } from "@/common/file";
|
||||||
import { ChatType, Peer } from "@/core";
|
import { ChatType, Peer } from "@/core";
|
||||||
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
character: Type.String(),
|
||||||
properties: {
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
character: { type: ['string'] },
|
text: Type.String(),
|
||||||
group_id: { type: ['number', 'string'] },
|
});
|
||||||
text: { type: 'string' },
|
|
||||||
},
|
type Payload = Static<typeof SchemaData>;
|
||||||
required: ['character', 'group_id', 'text'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
|
export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
|
||||||
message_id: number
|
message_id: number
|
||||||
@@ -26,7 +23,7 @@ export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
||||||
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
||||||
const { path, errMsg, success } = (await uri2local(this.core.NapCatTempPath, url));
|
const { path, errMsg, success } = (await uriToLocalFile(this.core.NapCatTempPath, url));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +1,20 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
import { MessageUnique } from '@/common/message-unique';
|
import { MessageUnique } from '@/common/message-unique';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
message_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
});
|
||||||
message_id: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['message_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class SetEssenceMsg extends OneBotAction<Payload, any> {
|
export default class SetEssenceMsg extends OneBotAction<Payload, any> {
|
||||||
actionName = ActionName.SetEssenceMsg;
|
actionName = ActionName.SetEssenceMsg;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<any> {
|
async _handle(payload: Payload): Promise<any> {
|
||||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
throw new Error('msg not found');
|
throw new Error('msg not found');
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,15 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { NTGroupRequestOperateTypes } from '@/core/types';
|
import { NTGroupRequestOperateTypes } from '@/core/types';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
flag: Type.Union([Type.String(), Type.Number()]),
|
||||||
properties: {
|
approve: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
|
||||||
flag: { type: 'string' },
|
reason: Type.Optional(Type.Union([Type.String({ default: ' ' }), Type.Null()])),
|
||||||
approve: { type: ['string', 'boolean'] },
|
});
|
||||||
reason: { type: 'string', nullable: true },
|
|
||||||
},
|
|
||||||
required: ['flag'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class SetGroupAddRequest extends OneBotAction<Payload, null> {
|
export default class SetGroupAddRequest extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.SetGroupAddRequest;
|
actionName = ActionName.SetGroupAddRequest;
|
||||||
@@ -22,10 +18,26 @@ export default class SetGroupAddRequest extends OneBotAction<Payload, null> {
|
|||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const flag = payload.flag.toString();
|
const flag = payload.flag.toString();
|
||||||
const approve = payload.approve?.toString() !== 'false';
|
const approve = payload.approve?.toString() !== 'false';
|
||||||
await this.core.apis.GroupApi.handleGroupRequest(flag,
|
const reason = payload.reason ?? ' ';
|
||||||
|
|
||||||
|
let notify = await this.findNotify(flag);
|
||||||
|
if (!notify) {
|
||||||
|
throw new Error('No such request');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.core.apis.GroupApi.handleGroupRequest(
|
||||||
|
notify,
|
||||||
approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,
|
approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,
|
||||||
payload.reason ?? ' ',
|
reason,
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async findNotify(flag: string) {
|
||||||
|
let notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(false, 100)).find(e => e.seq == flag);
|
||||||
|
if (!notify) {
|
||||||
|
notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(true, 100)).find(e => e.seq == flag);
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,19 +1,15 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { NTGroupMemberRole } from '@/core/types';
|
import { NTGroupMemberRole } from '@/core/types';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
group_id: { type: ['number', 'string'] },
|
enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
|
||||||
user_id: { type: ['number', 'string'] },
|
});
|
||||||
enable: { type: ['boolean', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'user_id'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class SetGroupAdmin extends OneBotAction<Payload, null> {
|
export default class SetGroupAdmin extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.SetGroupAdmin;
|
actionName = ActionName.SetGroupAdmin;
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = Type.Object({
|
||||||
type: 'object',
|
group_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
properties: {
|
user_id: Type.Union([Type.Number(), Type.String()]),
|
||||||
group_id: { type: ['number', 'string'] },
|
duration: Type.Union([Type.Number(), Type.String()], { default: 0 }),
|
||||||
user_id: { type: ['number', 'string'] },
|
});
|
||||||
duration: { type: ['number', 'string'] },
|
|
||||||
},
|
|
||||||
required: ['group_id', 'user_id', 'duration'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
export default class SetGroupBan extends OneBotAction<Payload, null> {
|
export default class SetGroupBan extends OneBotAction<Payload, null> {
|
||||||
actionName = ActionName.SetGroupBan;
|
actionName = ActionName.SetGroupBan;
|
||||||
@@ -22,7 +18,7 @@ export default class SetGroupBan extends OneBotAction<Payload, null> {
|
|||||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
if (!uid) throw new Error('uid error');
|
if (!uid) throw new Error('uid error');
|
||||||
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
||||||
[{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]);
|
[{ uid: uid, timeStamp: +payload.duration}]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user