mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c20362e9b6 | ||
![]() |
c90cfb99bd | ||
![]() |
7bcea14799 | ||
![]() |
b415c1a6d1 | ||
![]() |
452c72d280 | ||
![]() |
48350be625 | ||
![]() |
ab824fb219 | ||
![]() |
043d8a1861 | ||
![]() |
074ac15d0f | ||
![]() |
d36a28fa81 | ||
![]() |
ba12bc6c91 | ||
![]() |
87332778e5 | ||
![]() |
453feb8473 | ||
![]() |
8ff469974c | ||
![]() |
994ec5ac0f | ||
![]() |
43f7f9a363 | ||
![]() |
4a11ebc9b9 | ||
![]() |
d76a1305e7 | ||
![]() |
6a0d592491 | ||
![]() |
9898c2196d | ||
![]() |
41a8dc840f | ||
![]() |
c3eaae9d88 | ||
![]() |
3ca959b7a6 | ||
![]() |
1d2e2b6e5c | ||
![]() |
31d963c4d1 | ||
![]() |
7e96118cdc | ||
![]() |
709a0744bd | ||
![]() |
f59248cc5a | ||
![]() |
8647c5c607 | ||
![]() |
6699ff38a1 | ||
![]() |
d79b98bd55 | ||
![]() |
5065a052fb | ||
![]() |
45603bb78c | ||
![]() |
40948995b4 | ||
![]() |
4ccdd8d1d3 | ||
![]() |
30d0174f47 | ||
![]() |
5a986ba25c | ||
![]() |
fe63c24ac3 | ||
![]() |
c384bd6875 | ||
![]() |
dcbff3f569 | ||
![]() |
7d91e05a69 | ||
![]() |
a5ce424a40 | ||
![]() |
47c36ca062 | ||
![]() |
c4c5b3bf8b | ||
![]() |
b1a81b0d12 | ||
![]() |
ad9fe64850 | ||
![]() |
f236349dc6 | ||
![]() |
5f56c8a7d4 | ||
![]() |
309d8a9f18 | ||
![]() |
2981799803 | ||
![]() |
00f8e1c0da | ||
![]() |
e9482e2ec4 | ||
![]() |
9bff327377 | ||
![]() |
ae009f98c1 | ||
![]() |
77505a6f5b | ||
![]() |
19c729aa23 | ||
![]() |
595888128a | ||
![]() |
51589d0eae | ||
![]() |
f1643ac549 | ||
![]() |
3f24461612 | ||
![]() |
b5deb198de | ||
![]() |
78452cf6a9 | ||
![]() |
4b4a784f56 | ||
![]() |
3e53cbcf8f | ||
![]() |
f34740f1f0 | ||
![]() |
b406bdfc37 | ||
![]() |
03c056702c | ||
![]() |
9c5f3f1946 | ||
![]() |
b50d7c24e7 | ||
![]() |
f05cf68945 | ||
![]() |
efc1875e35 | ||
![]() |
df063e6762 | ||
![]() |
e5c55b4339 | ||
![]() |
bee9095d6f | ||
![]() |
92f8eaaac9 | ||
![]() |
f5e7288fe5 | ||
![]() |
214aa7b6e4 | ||
![]() |
5b5d5b41f5 | ||
![]() |
23d613321e | ||
![]() |
0b6be0923f | ||
![]() |
aba748ea13 | ||
![]() |
f1f1ac582d | ||
![]() |
54a7cbc3f4 | ||
![]() |
2f4dbaec4c | ||
![]() |
578f518aaf | ||
![]() |
077ba74b22 |
@@ -17,5 +17,8 @@ charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.bat]
|
||||
charset = latin1
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
|
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -1,15 +1,11 @@
|
||||
name: "Build Action"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
Build-LiteLoader:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
@@ -37,7 +33,6 @@ jobs:
|
||||
name: NapCat.Framework
|
||||
path: dist
|
||||
Build-Shell:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
@@ -63,4 +58,4 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.Shell
|
||||
path: dist
|
||||
path: dist
|
||||
|
@@ -7,10 +7,14 @@
|
||||
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现。
|
||||
|
||||
## 猫猫技能
|
||||
- [x] **高性能**:1K+ 群聊数目、20 线程并行发送消息毫无压力
|
||||
- [x] **多种启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **多平台支持**: 支持Windows/Linux(可选Docker)/Android Termux/MacOs覆盖全平台
|
||||
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
|
||||
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **超多接口**:在实现大部分Onebot接口上扩展了一套私有API
|
||||
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
|
||||
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
|
||||
- [x] **低故障率**:快速适配最新版本,日常保证 0 Issue
|
||||
|
||||
## 使用猫猫
|
||||
|
||||
|
BIN
launcher/NapCatWinBootHook.dll
Normal file
BIN
launcher/NapCatWinBootHook.dll
Normal file
Binary file not shown.
BIN
launcher/NapCatWinBootMain.exe
Normal file
BIN
launcher/NapCatWinBootMain.exe
Normal file
Binary file not shown.
39
launcher/launcher-win10.bat
Normal file
39
launcher/launcher-win10.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'cmd.exe' -ArgumentList '/c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in (%RetString%) do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
REM 拿不到QQ路径则退出
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
|
39
launcher/launcher.bat
Normal file
39
launcher/launcher.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'wt.exe' -ArgumentList 'cmd /c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
:: %RetString% 增加引号,解决QQ目录包含空格的问题,比如安装在:C:\Program Files\Tencent\QQNT
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
|
5
launcher/loadNapCat.js
Normal file
5
launcher/loadNapCat.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const path = require('path');
|
||||
const CurrentPath = path.dirname(__filename);
|
||||
(async () => {
|
||||
await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs'));
|
||||
})();
|
1
launcher/patchNapCat.js
Normal file
1
launcher/patchNapCat.js
Normal file
@@ -0,0 +1 @@
|
||||
require('./launcher.node').load('external_index', module);
|
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.2.26",
|
||||
"version": "2.3.0",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.2.26",
|
||||
"version": "2.3.0",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
|
Binary file not shown.
@@ -22,9 +22,14 @@ export abstract class ConfigBase<T> {
|
||||
}
|
||||
|
||||
getConfigPath(pathName: string | undefined): string {
|
||||
const suffix = pathName ? `_${pathName}` : '';
|
||||
const filename = `${this.name}${suffix}.json`;
|
||||
return path.join(this.configPath, filename);
|
||||
if (!pathName) {
|
||||
const filename = `${this.name}.json`;
|
||||
const mainPath = this.core.context.pathWrapper.binaryPath;
|
||||
return path.join(mainPath, 'config', filename);
|
||||
} else {
|
||||
const filename = `${this.name}_${pathName}.json`;
|
||||
return path.join(this.configPath, filename);
|
||||
}
|
||||
}
|
||||
|
||||
read(): T {
|
||||
|
@@ -23,48 +23,55 @@ export async function solveAsyncProblem<T extends (...args: any[]) => Promise<an
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export class FileNapCatOneBotUUID {
|
||||
static encodeModelId(peer: Peer, modelId: string): string {
|
||||
return `NapCatOneBot-ModeldFile-${peer.chatType}-${peer.peerUid}-${modelId}`;
|
||||
static encodeModelId(peer: Peer, modelId: string, fileId: string): string {
|
||||
return `NapCatOneBot|ModelIdFile|${peer.chatType}|${peer.peerUid}|${modelId}|${fileId}`;
|
||||
}
|
||||
|
||||
static decodeModelId(uuid: string): undefined | {
|
||||
peer: Peer,
|
||||
modelId: string
|
||||
modelId: string,
|
||||
fileId: string
|
||||
} {
|
||||
if (!uuid.startsWith('NapCatOneBot-ModeldFile-')) return undefined;
|
||||
const data = uuid.split('-');
|
||||
if (data.length !== 5) return undefined;
|
||||
const [, , chatType, peerUid, modelId] = data;
|
||||
if (!uuid.startsWith('NapCatOneBot|ModelIdFile|')) return undefined;
|
||||
const data = uuid.split('|');
|
||||
if (data.length !== 6) return undefined;
|
||||
const [, , chatType, peerUid, modelId, fileId] = data;
|
||||
return {
|
||||
peer: {
|
||||
chatType: chatType as any,
|
||||
peerUid: peerUid
|
||||
peerUid: peerUid,
|
||||
},
|
||||
modelId,
|
||||
fileId
|
||||
};
|
||||
}
|
||||
|
||||
static encode(peer: Peer, msgId: string, elementId: string): string {
|
||||
return `NapCatOneBot-MsgFile-${peer.chatType}-${peer.peerUid}-${msgId}-${elementId}`;
|
||||
return `NapCatOneBot|MsgFile|${peer.chatType}|${peer.peerUid}|${msgId}|${elementId}`;
|
||||
}
|
||||
|
||||
static decode(uuid: string): undefined | {
|
||||
peer: Peer,
|
||||
msgId: string,
|
||||
elementId: string
|
||||
} {
|
||||
if (!uuid.startsWith('NapCatOneBot-MsgFile-')) return undefined;
|
||||
const data = uuid.split('-');
|
||||
if (!uuid.startsWith('NapCatOneBot|MsgFile|')) return undefined;
|
||||
const data = uuid.split('|');
|
||||
if (data.length !== 6) return undefined;
|
||||
const [, , chatType, peerUid, msgId, elementId] = data;
|
||||
return {
|
||||
peer: {
|
||||
chatType: chatType as any,
|
||||
peerUid: peerUid
|
||||
peerUid: peerUid,
|
||||
},
|
||||
msgId,
|
||||
elementId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
@@ -133,26 +140,38 @@ export function isEqual(obj1: any, obj2: any) {
|
||||
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
||||
if (os.platform() === 'linux') {
|
||||
return {
|
||||
baseVersion: '3.2.12-27254',
|
||||
curVersion: '3.2.12-27254',
|
||||
baseVersion: '3.2.12-27597',
|
||||
curVersion: '3.2.12-27597',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '27254',
|
||||
buildId: '27597',
|
||||
};
|
||||
}
|
||||
return {
|
||||
baseVersion: '9.9.15-27391',
|
||||
curVersion: '9.9.15-27391',
|
||||
baseVersion: '9.9.15-27597',
|
||||
curVersion: '9.9.15-27597',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '27391',
|
||||
buildId: '27597',
|
||||
};
|
||||
}
|
||||
|
||||
export function getQQPackageInfoPath(exePath: string = ''): string {
|
||||
if (os.platform() === 'darwin') {
|
||||
return path.join(path.dirname(exePath), '..', 'Resources', 'app', 'package.json');
|
||||
} else {
|
||||
return path.join(path.dirname(exePath), 'resources', 'app', 'package.json');
|
||||
}
|
||||
}
|
||||
|
||||
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
|
||||
let configVersionInfoPath;
|
||||
if (os.platform() !== 'linux') {
|
||||
if (os.platform() === 'win32') {
|
||||
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
|
||||
} else if (os.platform() === 'darwin') {
|
||||
const userPath = os.homedir();
|
||||
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
|
||||
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
|
||||
} else {
|
||||
const userPath = os.homedir();
|
||||
const appDataPath = path.resolve(userPath, './.config/QQ');
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import path, { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
export class NapCatPathWrapper {
|
||||
binaryPath: string;
|
||||
@@ -11,17 +12,23 @@ export class NapCatPathWrapper {
|
||||
|
||||
constructor(mainPath: string = dirname(fileURLToPath(import.meta.url))) {
|
||||
this.binaryPath = mainPath;
|
||||
this.logsPath = path.join(this.binaryPath, 'logs');
|
||||
this.configPath = path.join(this.binaryPath, 'config');
|
||||
this.cachePath = path.join(this.binaryPath, 'cache');
|
||||
let writePath: string;
|
||||
if (os.platform() === 'darwin') {
|
||||
writePath = path.join(os.homedir(), 'Library', 'Application Support', 'QQ', 'NapCat');
|
||||
} else {
|
||||
writePath = this.binaryPath;
|
||||
}
|
||||
this.logsPath = path.join(writePath, 'logs');
|
||||
this.configPath = path.join(writePath, 'config');
|
||||
this.cachePath = path.join(writePath, 'cache');
|
||||
this.staticPath = path.join(this.binaryPath, 'static');
|
||||
if (fs.existsSync(this.logsPath)) {
|
||||
if (!fs.existsSync(this.logsPath)) {
|
||||
fs.mkdirSync(this.logsPath, { recursive: true });
|
||||
}
|
||||
if (fs.existsSync(this.configPath)) {
|
||||
if (!fs.existsSync(this.configPath)) {
|
||||
fs.mkdirSync(this.configPath, { recursive: true });
|
||||
}
|
||||
if (fs.existsSync(this.cachePath)) {
|
||||
if (!fs.existsSync(this.cachePath)) {
|
||||
fs.mkdirSync(this.cachePath, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { systemPlatform } from '@/common/system';
|
||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
||||
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath } from './helper';
|
||||
import AppidTable from '@/core/external/appid.json';
|
||||
import { LogWrapper } from './log';
|
||||
|
||||
@@ -20,7 +19,7 @@ export class QQBasicInfoWrapper {
|
||||
//基础目录获取
|
||||
this.context = context;
|
||||
this.QQMainPath = process.execPath;
|
||||
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
|
||||
this.QQPackageInfoPath = getQQPackageInfoPath(this.QQMainPath);
|
||||
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
|
||||
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
@@ -53,9 +52,25 @@ export class QQBasicInfoWrapper {
|
||||
|
||||
//此方法不要直接使用
|
||||
getQUAInternal() {
|
||||
return systemPlatform === 'linux'
|
||||
? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`
|
||||
: `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||
switch (systemPlatform) {
|
||||
case 'linux':
|
||||
return `V1_LNX_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||
case 'darwin':
|
||||
return `V1_MAC_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||
default:
|
||||
return `V1_WIN_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||
}
|
||||
}
|
||||
|
||||
getAppidInternal() {
|
||||
switch (systemPlatform) {
|
||||
case 'linux':
|
||||
return '537243600';
|
||||
case 'darwin':
|
||||
return '537243441';
|
||||
default:
|
||||
return '537243538';
|
||||
}
|
||||
}
|
||||
|
||||
getAppidV2(): { appid: string; qua: string } {
|
||||
@@ -71,6 +86,6 @@ export class QQBasicInfoWrapper {
|
||||
// else
|
||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
|
||||
return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() };
|
||||
return { appid: this.getAppidInternal(), qua: this.getQUAInternal() };
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.2.26';
|
||||
export const napCatVersion = '2.3.0';
|
||||
|
@@ -16,7 +16,8 @@ export async function getVideoInfo(filePath: string, logger: LogWrapper) {
|
||||
filePath: string
|
||||
}>((resolve, reject) => {
|
||||
const ffmpegPath = process.env.FFMPEG_PATH;
|
||||
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath);
|
||||
if (ffmpegPath)
|
||||
ffmpeg.setFfmpegPath(ffmpegPath);
|
||||
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
|
63
src/core/apis/cache.ts
Normal file
63
src/core/apis/cache.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
CacheFileListItem,
|
||||
CacheFileType,
|
||||
ChatCacheListItemBasic,
|
||||
ChatType,
|
||||
InstanceContext,
|
||||
NapCatCore,
|
||||
} from '@/core';
|
||||
|
||||
export class NTQQCacheApi {
|
||||
context: InstanceContext;
|
||||
core: NapCatCore;
|
||||
|
||||
constructor(context: InstanceContext, core: NapCatCore) {
|
||||
this.context = context;
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async setCacheSilentScan(isSilent: boolean = true) {
|
||||
return '';
|
||||
}
|
||||
|
||||
getCacheSessionPathList() {
|
||||
return '';
|
||||
}
|
||||
|
||||
clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
|
||||
// 参数未验证
|
||||
return this.context.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys);
|
||||
}
|
||||
|
||||
addCacheScannedPaths(pathMap: object = {}) {
|
||||
return this.context.session.getStorageCleanService().addCacheScanedPaths(pathMap);
|
||||
}
|
||||
|
||||
scanCache() {
|
||||
//return (await this.context.session.getStorageCleanService().scanCache()).size;
|
||||
}
|
||||
|
||||
getHotUpdateCachePath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
getDesktopTmpPath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
|
||||
return this.context.session.getStorageCleanService().getChatCacheInfo(type, pageSize, 1, pageIndex);
|
||||
}
|
||||
|
||||
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
|
||||
// const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
|
||||
// 需要五个参数
|
||||
// return napCatCore.session.getStorageCleanService().getFileCacheInfo();
|
||||
}
|
||||
|
||||
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
|
||||
return this.context.session.getStorageCleanService().clearChatCacheInfo(chats, fileKeys);
|
||||
}
|
||||
}
|
@@ -10,7 +10,7 @@ export class NTQQCollectionApi {
|
||||
}
|
||||
|
||||
async createCollection(authorUin: string, authorUid: string, authorName: string, brief: string, rawData: string) {
|
||||
const param = {
|
||||
return this.context.session.getCollectionService().createNewCollectionItem({
|
||||
commInfo: {
|
||||
bid: 1,
|
||||
category: 2,
|
||||
@@ -43,12 +43,11 @@ export class NTQQCollectionApi {
|
||||
fileList: [],
|
||||
},
|
||||
need_share_url: false,
|
||||
};
|
||||
return this.context.session.getCollectionService().createNewCollectionItem(param);
|
||||
});
|
||||
}
|
||||
|
||||
async getAllCollection(category: number = 0, count: number = 50) {
|
||||
const param = {
|
||||
return this.context.session.getCollectionService().getCollectionItemList({
|
||||
category: category,
|
||||
groupId: -1,
|
||||
forceSync: true,
|
||||
@@ -56,7 +55,6 @@ export class NTQQCollectionApi {
|
||||
timeStamp: '0',
|
||||
count: count,
|
||||
searchDown: true,
|
||||
};
|
||||
return this.context.session.getCollectionService().getCollectionItemList(param);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
CacheFileListItem,
|
||||
CacheFileType,
|
||||
ChatCacheListItemBasic,
|
||||
ChatType,
|
||||
ElementType,
|
||||
IMAGE_HTTP_HOST,
|
||||
@@ -26,10 +23,8 @@ import { calculateFileMD5, isGIF } from '@/common/file';
|
||||
import pathLib from 'node:path';
|
||||
import { defaultVideoThumbB64, getVideoInfo } from '@/common/video';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import fsnormal from 'node:fs';
|
||||
import { encodeSilk } from '@/common/audio';
|
||||
|
||||
|
||||
export class NTQQFileApi {
|
||||
context: InstanceContext;
|
||||
core: NapCatCore;
|
||||
@@ -41,10 +36,6 @@ export class NTQQFileApi {
|
||||
this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger);
|
||||
}
|
||||
|
||||
async getFileType(filePath: string) {
|
||||
return fileType.fileTypeFromFile(filePath);
|
||||
}
|
||||
|
||||
async copyFile(filePath: string, destPath: string) {
|
||||
await this.core.util.copyFile(filePath, destPath);
|
||||
}
|
||||
@@ -60,18 +51,15 @@ export class NTQQFileApi {
|
||||
})).urlResult.domainUrl;
|
||||
}
|
||||
|
||||
// 上传文件到QQ的文件夹
|
||||
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
||||
// napCatCore.wrapper.util.
|
||||
const fileMd5 = await calculateFileMD5(filePath);
|
||||
let ext: string = (await this.getFileType(filePath))?.ext as string || '';
|
||||
if (ext) {
|
||||
ext = '.' + ext;
|
||||
}
|
||||
const extOrEmpty = (await fileType.fileTypeFromFile(filePath))?.ext;
|
||||
const ext = extOrEmpty ? `.${extOrEmpty}` : '';
|
||||
let fileName = `${path.basename(filePath)}`;
|
||||
if (fileName.indexOf('.') === -1) {
|
||||
fileName += ext;
|
||||
}
|
||||
|
||||
const mediaPath = this.context.session.getMsgService().getRichMediaFilePathForGuild({
|
||||
md5HexStr: fileMd5,
|
||||
fileName: fileName,
|
||||
@@ -82,6 +70,7 @@ export class NTQQFileApi {
|
||||
downloadType: 1,
|
||||
file_uuid: '',
|
||||
});
|
||||
|
||||
await this.copyFile(filePath, mediaPath!);
|
||||
const fileSize = await this.getFileSize(filePath);
|
||||
return {
|
||||
@@ -93,11 +82,7 @@ export class NTQQFileApi {
|
||||
};
|
||||
}
|
||||
|
||||
async createValidSendFileElement(
|
||||
filePath: string,
|
||||
fileName: string = '',
|
||||
folderId: string = '',
|
||||
): Promise<SendFileElement> {
|
||||
async createValidSendFileElement(filePath: string, fileName: string = '', folderId: string = '',): Promise<SendFileElement> {
|
||||
const {
|
||||
fileName: _fileName,
|
||||
path,
|
||||
@@ -118,55 +103,36 @@ export class NTQQFileApi {
|
||||
};
|
||||
}
|
||||
|
||||
async createValidSendPicElement(
|
||||
picPath: string,
|
||||
summary: string = '',
|
||||
subType: 0 | 1 = 0,
|
||||
): Promise<SendPicElement> {
|
||||
const {
|
||||
md5,
|
||||
fileName,
|
||||
path,
|
||||
fileSize,
|
||||
} = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
|
||||
async createValidSendPicElement(picPath: string, summary: string = '', subType: 0 | 1 = 0,): Promise<SendPicElement> {
|
||||
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
|
||||
if (fileSize === 0) {
|
||||
throw new Error('文件异常,大小为0');
|
||||
}
|
||||
const imageSize = await this.core.apis.FileApi.getImageSize(picPath);
|
||||
const picElement: any = {
|
||||
md5HexStr: md5,
|
||||
fileSize: fileSize.toString(),
|
||||
picWidth: imageSize?.width,
|
||||
picHeight: imageSize?.height,
|
||||
fileName: fileName,
|
||||
sourcePath: path,
|
||||
original: true,
|
||||
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
|
||||
picSubType: subType,
|
||||
fileUuid: '',
|
||||
fileSubId: '',
|
||||
thumbFileSize: 0,
|
||||
summary,
|
||||
};
|
||||
return {
|
||||
elementType: ElementType.PIC,
|
||||
elementId: '',
|
||||
picElement,
|
||||
picElement: {
|
||||
md5HexStr: md5,
|
||||
fileSize: fileSize.toString(),
|
||||
picWidth: imageSize.width,
|
||||
picHeight: imageSize.height,
|
||||
fileName: fileName,
|
||||
sourcePath: path,
|
||||
original: true,
|
||||
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
|
||||
picSubType: subType,
|
||||
fileUuid: '',
|
||||
fileSubId: '',
|
||||
thumbFileSize: 0,
|
||||
summary,
|
||||
} as PicElement,
|
||||
};
|
||||
}
|
||||
|
||||
async createValidSendVideoElement(
|
||||
filePath: string,
|
||||
fileName: string = '',
|
||||
diyThumbPath: string = '',
|
||||
): Promise<SendVideoElement> {
|
||||
async createValidSendVideoElement(filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise<SendVideoElement> {
|
||||
const logger = this.core.context.logger;
|
||||
const {
|
||||
fileName: _fileName,
|
||||
path,
|
||||
fileSize,
|
||||
md5,
|
||||
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
|
||||
const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
|
||||
if (fileSize === 0) {
|
||||
throw new Error('文件异常,大小为0');
|
||||
}
|
||||
@@ -182,9 +148,10 @@ export class NTQQFileApi {
|
||||
try {
|
||||
videoInfo = await getVideoInfo(path, logger);
|
||||
} catch (e) {
|
||||
logger.logError('获取视频信息失败', e);
|
||||
logger.logError('获取视频信息失败,将使用默认值', e);
|
||||
}
|
||||
const createThumb = new Promise<string | undefined>((resolve, reject) => {
|
||||
const thumbPath = new Map();
|
||||
const _thumbPath = await new Promise<string | undefined>((resolve, reject) => {
|
||||
const thumbFileName = `${md5}_0.png`;
|
||||
const thumbPath = pathLib.join(thumb, thumbFileName);
|
||||
ffmpeg(filePath)
|
||||
@@ -195,7 +162,7 @@ export class NTQQFileApi {
|
||||
resolve(thumbPath);
|
||||
}).catch(reject);
|
||||
} else {
|
||||
fsnormal.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
|
||||
fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
|
||||
resolve(thumbPath);
|
||||
}
|
||||
})
|
||||
@@ -204,31 +171,14 @@ export class NTQQFileApi {
|
||||
filename: thumbFileName,
|
||||
folder: thumb,
|
||||
size: videoInfo.width + 'x' + videoInfo.height,
|
||||
}).on('end', () => {
|
||||
})
|
||||
.on('end', () => {
|
||||
resolve(thumbPath);
|
||||
});
|
||||
});
|
||||
const thumbPath = new Map();
|
||||
const _thumbPath = await createThumb;
|
||||
const thumbSize = _thumbPath ? (await fsPromises.stat(_thumbPath)).size : 0;
|
||||
// log("生成缩略图", _thumbPath)
|
||||
thumbPath.set(0, _thumbPath);
|
||||
const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : '';
|
||||
// "fileElement": {
|
||||
// "fileMd5": "",
|
||||
// "fileName": "1.mp4",
|
||||
// "filePath": "C:\\Users\\nanae\\OneDrive\\Desktop\\1.mp4",
|
||||
// "fileSize": "1847007",
|
||||
// "picHeight": 1280,
|
||||
// "picWidth": 720,
|
||||
// "picThumbPath": {},
|
||||
// "file10MMd5": "",
|
||||
// "fileSha": "",
|
||||
// "fileSha3": "",
|
||||
// "fileUuid": "",
|
||||
// "fileSubId": "",
|
||||
// "thumbFileSize": 750
|
||||
// }
|
||||
return {
|
||||
elementType: ElementType.VIDEO,
|
||||
elementId: '',
|
||||
@@ -243,28 +193,12 @@ export class NTQQFileApi {
|
||||
thumbWidth: videoInfo.width,
|
||||
thumbHeight: videoInfo.height,
|
||||
fileSize: '' + fileSize,
|
||||
// fileFormat: videotype
|
||||
// fileUuid: "",
|
||||
// transferStatus: 0,
|
||||
// progress: 0,
|
||||
// invalidState: 0,
|
||||
// fileSubId: "",
|
||||
// fileBizId: null,
|
||||
// originVideoMd5: "",
|
||||
// fileFormat: 2,
|
||||
// import_rich_media_context: null,
|
||||
// sourceVideoCodecFormat: 2
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async createValidSendPttElement(pttPath: string): Promise<SendPttElement> {
|
||||
const {
|
||||
converted,
|
||||
path: silkPath,
|
||||
duration,
|
||||
} = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
||||
// 生成语音 Path: silkPath Time: duration
|
||||
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
|
||||
if (!silkPath) {
|
||||
throw new Error('语音转换失败, 请检查语音文件是否正常');
|
||||
}
|
||||
@@ -283,7 +217,6 @@ export class NTQQFileApi {
|
||||
filePath: path,
|
||||
md5HexStr: md5,
|
||||
fileSize: fileSize,
|
||||
// duration: Math.max(1, Math.round(fileSize / 1024 / 3)), // 一秒钟大概是3kb大小, 小于1秒的按1秒算
|
||||
duration: duration ?? 1,
|
||||
formatType: 1,
|
||||
voiceType: 1,
|
||||
@@ -299,14 +232,11 @@ export class NTQQFileApi {
|
||||
};
|
||||
}
|
||||
|
||||
async downloadMediaByUuid() {
|
||||
//napCatCore.session.getRichMediaService().downloadFileForFileUuid();
|
||||
}
|
||||
async downloadFileForModelId(peer: Peer, modelId: string, timeout = 1000 * 60 * 2) {
|
||||
async downloadFileForModelId(peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) {
|
||||
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelRichMediaService/downloadFileForModelId',
|
||||
'NodeIKernelMsgListener/onRichMediaDownloadComplete',
|
||||
[peer, [modelId]],
|
||||
[peer, [modelId], unknown],
|
||||
() => true,
|
||||
(arg) => arg?.commonFileInfo?.fileModelId === modelId,
|
||||
1,
|
||||
@@ -314,6 +244,7 @@ export class NTQQFileApi {
|
||||
);
|
||||
return fileTransNotifyInfo.filePath;
|
||||
}
|
||||
|
||||
async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
|
||||
//logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
|
||||
// 用于下载收到的消息中的图片等
|
||||
@@ -328,7 +259,7 @@ export class NTQQFileApi {
|
||||
return sourcePath;
|
||||
}
|
||||
}
|
||||
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
|
||||
const [, completeRetData] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelMsgService/downloadRichMedia',
|
||||
'NodeIKernelMsgListener/onRichMediaDownloadComplete',
|
||||
[{
|
||||
@@ -348,29 +279,20 @@ export class NTQQFileApi {
|
||||
1,
|
||||
timeout,
|
||||
);
|
||||
const msg = await this.core.apis.MsgApi.getMsgsByMsgId({
|
||||
guildId: '',
|
||||
chatType: chatType,
|
||||
peerUid: peerUid,
|
||||
}, [msgId]);
|
||||
const mixElement = msg.msgList.find((msg) => msg.msgId === msgId)?.elements.find((e) => e.elementId === elementId);
|
||||
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||
let realPath = mixElementInner?.filePath;
|
||||
if (!realPath) {
|
||||
const picThumbPath: Map<number, string> = (mixElementInner as any)?.picThumbPath;
|
||||
const picThumbPathList = Array.from(picThumbPath.values());
|
||||
if (picThumbPathList.length > 0) realPath = picThumbPathList[0];
|
||||
}
|
||||
return realPath;
|
||||
return completeRetData.filePath;
|
||||
}
|
||||
|
||||
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
|
||||
async getImageSize(filePath: string): Promise<ISizeCalculationResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
imageSize(filePath, (err, dimensions) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(dimensions);
|
||||
if (!dimensions) {
|
||||
reject(new Error('获取图片尺寸失败'));
|
||||
} else {
|
||||
resolve(dimensions);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -436,16 +358,21 @@ export class NTQQFileApi {
|
||||
}
|
||||
|
||||
async searchForFile(keys: string[]): Promise<SearchResultItem | undefined> {
|
||||
const randomResultId = 100000 + Math.floor(Math.random() * 10000);
|
||||
let searchId = 0;
|
||||
const [, searchResult] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelFileAssistantService/searchFile',
|
||||
'NodeIKernelFileAssistantListener/onFileSearch',
|
||||
[
|
||||
keys,
|
||||
{
|
||||
resultType: 2,
|
||||
pageLimit: 1,
|
||||
}
|
||||
]
|
||||
{ resultType: 2, pageLimit: 1 },
|
||||
randomResultId,
|
||||
],
|
||||
(ret) => {
|
||||
searchId = ret;
|
||||
return true;
|
||||
},
|
||||
result => result.searchId === searchId && result.resultId === randomResultId,
|
||||
);
|
||||
return searchResult.resultItems[0];
|
||||
}
|
||||
@@ -455,7 +382,7 @@ export class NTQQFileApi {
|
||||
fileSize: number = 1024576,
|
||||
estimatedTime: number = (fileSize * 1000 / 1024576) + 5000,
|
||||
) {
|
||||
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
|
||||
const [, fileData] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelFileAssistantService/downloadFile',
|
||||
'NodeIKernelFileAssistantListener/onFileStatusChanged',
|
||||
[[fileId]],
|
||||
@@ -464,7 +391,7 @@ export class NTQQFileApi {
|
||||
1,
|
||||
estimatedTime, // estimate 1MB/s
|
||||
);
|
||||
return ret.filePath!;
|
||||
return fileData.filePath!;
|
||||
}
|
||||
|
||||
async getImageUrl(element: PicElement) {
|
||||
@@ -474,20 +401,19 @@ export class NTQQFileApi {
|
||||
const url: string = element.originImageUrl!; // 没有域名
|
||||
const md5HexStr = element.md5HexStr;
|
||||
const fileMd5 = element.md5HexStr;
|
||||
// const fileUuid = element.fileUuid;
|
||||
|
||||
if (url) {
|
||||
const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
|
||||
const imageAppid = UrlParse.searchParams.get('appid');
|
||||
const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||
if (isNewPic) {
|
||||
let UrlRkey = UrlParse.searchParams.get('rkey');
|
||||
if (UrlRkey) {
|
||||
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
|
||||
const imageAppid = parsedUrl.searchParams.get('appid');
|
||||
const isNTFlavoredPic = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||
if (isNTFlavoredPic) {
|
||||
let rkey = parsedUrl.searchParams.get('rkey');
|
||||
if (rkey) {
|
||||
return IMAGE_HTTP_HOST_NT + url;
|
||||
}
|
||||
const rkeyData = await this.rkeyManager.getRkey();
|
||||
UrlRkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST_NT + url + `${UrlRkey}`;
|
||||
rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST_NT + url + `${rkey}`;
|
||||
} else {
|
||||
// 老的图片url,不需要rkey
|
||||
return IMAGE_HTTP_HOST + url;
|
||||
@@ -501,57 +427,3 @@ export class NTQQFileApi {
|
||||
}
|
||||
}
|
||||
|
||||
export class NTQQFileCacheApi {
|
||||
context: InstanceContext;
|
||||
core: NapCatCore;
|
||||
|
||||
constructor(context: InstanceContext, core: NapCatCore) {
|
||||
this.context = context;
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async setCacheSilentScan(isSilent: boolean = true) {
|
||||
return '';
|
||||
}
|
||||
|
||||
getCacheSessionPathList() {
|
||||
return '';
|
||||
}
|
||||
|
||||
clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
|
||||
// 参数未验证
|
||||
return this.context.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys);
|
||||
}
|
||||
|
||||
addCacheScannedPaths(pathMap: object = {}) {
|
||||
return this.context.session.getStorageCleanService().addCacheScanedPaths(pathMap);
|
||||
}
|
||||
|
||||
scanCache() {
|
||||
//return (await this.context.session.getStorageCleanService().scanCache()).size;
|
||||
}
|
||||
|
||||
getHotUpdateCachePath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
getDesktopTmpPath() {
|
||||
// 未实现
|
||||
return '';
|
||||
}
|
||||
|
||||
getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
|
||||
return this.context.session.getStorageCleanService().getChatCacheInfo(type, pageSize, 1, pageIndex);
|
||||
}
|
||||
|
||||
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
|
||||
// const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
|
||||
// 需要五个参数
|
||||
// return napCatCore.session.getStorageCleanService().getFileCacheInfo();
|
||||
}
|
||||
|
||||
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
|
||||
return this.context.session.getStorageCleanService().clearChatCacheInfo(chats, fileKeys);
|
||||
}
|
||||
}
|
||||
|
@@ -16,47 +16,42 @@ export class NTQQFriendApi {
|
||||
// }
|
||||
}
|
||||
|
||||
async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||
const uids: string[] = [];
|
||||
async getBuddyV2SimpleInfoMap(refresh = false) {
|
||||
const buddyService = this.context.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
||||
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
|
||||
const data = await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
|
||||
const uids = buddyListV2.data.flatMap(item => item.buddyUids);
|
||||
return await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
||||
'nodeStore',
|
||||
uids,
|
||||
);
|
||||
return Array.from(data.values());
|
||||
}
|
||||
|
||||
async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||
return Array.from((await this.getBuddyV2SimpleInfoMap(refresh)).values());
|
||||
}
|
||||
|
||||
async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||
const uids: string[] = [];
|
||||
const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000);
|
||||
const buddyService = this.context.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
||||
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
|
||||
const data = await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
|
||||
);
|
||||
data.forEach((value) => {
|
||||
retMap.set(value.uin!, value.uid!);
|
||||
});
|
||||
//console.log('getBuddyIdMap', retMap.getValue);
|
||||
const data = await this.getBuddyV2SimpleInfoMap(refresh);
|
||||
data.forEach((value) => retMap.set(value.uin!, value.uid!));
|
||||
return retMap;
|
||||
}
|
||||
|
||||
async getBuddyV2ExWithCate(refresh = false) {
|
||||
const uids: string[] = [];
|
||||
const categoryMap: Map<string, any> = new Map();
|
||||
const buddyService = this.context.session.getBuddyService();
|
||||
const buddyListV2 = refresh ? (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data : (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data;
|
||||
uids.push(
|
||||
...buddyListV2.flatMap(item => {
|
||||
item.buddyUids.forEach(uid => {
|
||||
categoryMap.set(uid, { categoryId: item.categoryId, categoryName: item.categroyName });
|
||||
});
|
||||
return item.buddyUids;
|
||||
}));
|
||||
const uids = buddyListV2.flatMap(item => {
|
||||
item.buddyUids.forEach(uid => {
|
||||
categoryMap.set(uid, { categoryId: item.categoryId, categoryName: item.categroyName });
|
||||
});
|
||||
return item.buddyUids;
|
||||
});
|
||||
const data = await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
||||
'nodeStore',
|
||||
uids,
|
||||
);
|
||||
return buddyListV2.map(category => ({
|
||||
categoryId: category.categoryId,
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
ChatType,
|
||||
GeneralCallResult,
|
||||
Group,
|
||||
GroupInfoSource,
|
||||
GroupMember,
|
||||
GroupMemberRole,
|
||||
GroupRequestOperateTypes,
|
||||
@@ -11,7 +9,7 @@ import {
|
||||
MemberExtSourceType,
|
||||
NapCatCore,
|
||||
} from '@/core';
|
||||
import { isNumeric, runAllWithTimeout } from '@/common/helper';
|
||||
import { isNumeric } from '@/common/helper';
|
||||
import { LimitedHashTable } from '@/common/message-unique';
|
||||
|
||||
export class NTQQGroupApi {
|
||||
@@ -35,17 +33,20 @@ export class NTQQGroupApi {
|
||||
}
|
||||
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
|
||||
}
|
||||
|
||||
async fetchGroupEssenceList(groupCode: string) {
|
||||
const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
||||
return this.context.session.getGroupService().fetchGroupEssenceList({
|
||||
groupCode: groupCode,
|
||||
pageStart: 0,
|
||||
pageLimit: 300
|
||||
pageLimit: 300,
|
||||
}, pskey);
|
||||
}
|
||||
|
||||
async clearGroupNotifiesUnreadCount(unk: boolean) {
|
||||
return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(unk);
|
||||
}
|
||||
|
||||
async setGroupAvatar(gc: string, filePath: string) {
|
||||
return this.context.session.getGroupService().setHeader(gc, filePath);
|
||||
}
|
||||
@@ -58,6 +59,7 @@ export class NTQQGroupApi {
|
||||
);
|
||||
return groupList;
|
||||
}
|
||||
|
||||
async getGroupExtFE0Info(GroupCode: string[], forced = true) {
|
||||
return this.context.session.getGroupService().getGroupExt0xEF0Info(
|
||||
GroupCode,
|
||||
@@ -94,11 +96,12 @@ export class NTQQGroupApi {
|
||||
showPlayTogetherSwitch: 1,
|
||||
starId: 1,
|
||||
todoSeq: 1,
|
||||
viewedMsgDisappearTime: 1
|
||||
viewedMsgDisappearTime: 1,
|
||||
},
|
||||
forced
|
||||
forced,
|
||||
);
|
||||
}
|
||||
|
||||
async getGroup(groupCode: string, forced = false) {
|
||||
let group = this.groupCache.get(groupCode.toString());
|
||||
if (!group) {
|
||||
@@ -117,62 +120,6 @@ export class NTQQGroupApi {
|
||||
return group;
|
||||
}
|
||||
|
||||
async getGroupMemberLatestSendTimeCache(GroupCode: string, uids: string[]) {
|
||||
return this.getGroupMemberLatestSendTime(GroupCode, uids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
|
||||
* @param GroupCode 群号
|
||||
* @param uids QQ号
|
||||
* @returns Map<string, string> key: uin value: sendTime
|
||||
* @example
|
||||
* let ret = await NTQQGroupApi.getGroupMemberLastestSendTime('123456');
|
||||
* for (let [uin, sendTime] of ret) {
|
||||
* console.log(uin, sendTime);
|
||||
* }
|
||||
*/
|
||||
async getGroupMemberLatestSendTime(GroupCode: string, uids: string[]) {
|
||||
const getdata = async (uid: string) => {
|
||||
const NTRet = await this.getLatestMsgByUids(GroupCode, [uid]);
|
||||
if (NTRet.result != 0 && NTRet.msgList.length < 1) {
|
||||
return undefined;
|
||||
}
|
||||
return { sendUin: NTRet.msgList[0].senderUin, sendTime: NTRet.msgList[0].msgTime };
|
||||
};
|
||||
const PromiseData: Promise<({
|
||||
sendUin: string;
|
||||
sendTime: string;
|
||||
} | undefined)>[] = [];
|
||||
const ret: Map<string, string> = new Map();
|
||||
for (const uid of uids) {
|
||||
PromiseData.push(getdata(uid).catch(() => undefined));
|
||||
}
|
||||
const allRet = await runAllWithTimeout(PromiseData, 2500);
|
||||
for (const PromiseDo of allRet) {
|
||||
if (PromiseDo) {
|
||||
ret.set(PromiseDo.sendUin, PromiseDo.sendTime);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
async getLatestMsgByUids(GroupCode: string, uids: string[]) {
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: {
|
||||
peerUid: GroupCode,
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
},
|
||||
filterMsgType: [],
|
||||
filterSendersUid: uids,
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
}
|
||||
|
||||
async getGroupMemberAll(GroupCode: string, forced = false) {
|
||||
return this.context.session.getGroupService().getAllMemberList(GroupCode, forced);
|
||||
}
|
||||
@@ -209,30 +156,6 @@ export class NTQQGroupApi {
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
async getLatestMsg(GroupCode: string, uins: string[]) {
|
||||
const uids: Array<string> = [];
|
||||
for (const uin of uins) {
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(uin);
|
||||
if (uid) {
|
||||
uids.push(uid);
|
||||
}
|
||||
}
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: {
|
||||
peerUid: GroupCode,
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
},
|
||||
filterMsgType: [],
|
||||
filterSendersUid: uids,
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
}
|
||||
|
||||
async getGroupRecommendContactArkJson(GroupCode: string) {
|
||||
return this.context.session.getGroupService().getGroupRecommendContactArkJson(GroupCode);
|
||||
}
|
||||
@@ -250,8 +173,7 @@ export class NTQQGroupApi {
|
||||
}
|
||||
|
||||
async addGroupEssence(GroupCode: string, msgId: string) {
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
// 需要 ob11msgId -> msgId + (peer) -> msgSeq + msgRandom
|
||||
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
||||
chatType: 2,
|
||||
guildId: '',
|
||||
@@ -262,7 +184,7 @@ export class NTQQGroupApi {
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
||||
};
|
||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
// GetMsgByShortID(shortID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
return this.context.session.getGroupService().addGroupEssence(param);
|
||||
}
|
||||
|
||||
@@ -271,8 +193,8 @@ export class NTQQGroupApi {
|
||||
}
|
||||
|
||||
async deleteGroupBulletin(GroupCode: string, noticeId: string) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
async quitGroupV2(GroupCode: string, needDeleteLocalMsg: boolean) {
|
||||
@@ -283,18 +205,17 @@ export class NTQQGroupApi {
|
||||
//应该是直接返回不需要Listener的 未经测试 需测试再发布
|
||||
return this.context.session.getGroupService().quitGroupV2(param);
|
||||
}
|
||||
|
||||
async removeGroupEssenceBySeq(GroupCode: string, msgRandom: string, msgSeq: string) {
|
||||
const param = {
|
||||
groupCode: GroupCode,
|
||||
msgRandom: parseInt(msgRandom),
|
||||
msgSeq: parseInt(msgSeq),
|
||||
};
|
||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
return this.context.session.getGroupService().removeGroupEssence(param);
|
||||
}
|
||||
|
||||
async removeGroupEssence(GroupCode: string, msgId: string) {
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
|
||||
chatType: 2,
|
||||
guildId: '',
|
||||
@@ -305,7 +226,6 @@ export class NTQQGroupApi {
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
|
||||
};
|
||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
||||
return this.context.session.getGroupService().removeGroupEssence(param);
|
||||
}
|
||||
|
||||
@@ -327,7 +247,7 @@ export class NTQQGroupApi {
|
||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||
1,
|
||||
forced ? 5000 : 250,
|
||||
(params) => params === GroupCode,
|
||||
(params, _, members) => params === GroupCode && members.size > 0,
|
||||
);
|
||||
const retData = await (
|
||||
this.core.eventWrapper
|
||||
@@ -362,7 +282,7 @@ export class NTQQGroupApi {
|
||||
if (membersFromFunc.status === 'fulfilled' && membersFromListener.status === 'fulfilled') {
|
||||
return new Map([
|
||||
...membersFromFunc.value.result.infos,
|
||||
...membersFromListener.value[0].infos
|
||||
...membersFromListener.value[0].infos,
|
||||
]);
|
||||
}
|
||||
if (membersFromFunc.status === 'fulfilled') {
|
||||
@@ -387,28 +307,12 @@ export class NTQQGroupApi {
|
||||
|
||||
this.context.logger.logDebug(`获取群(${groupQQ})成员列表结果:`, `members: ${result.result.infos.size}`); //, Array.from(result.result.infos.values()));
|
||||
return result.result.infos;
|
||||
/*
|
||||
console.log(sceneId);
|
||||
const result = await napCatCore.getGroupService().getNextMemberList(sceneId, num);
|
||||
console.log(result);
|
||||
|
||||
return result;
|
||||
*/
|
||||
}
|
||||
|
||||
async getGroupNotifies() {
|
||||
// 获取管理员变更
|
||||
// 加群通知,退出通知,需要管理员权限
|
||||
|
||||
}
|
||||
|
||||
async GetGroupFileCount(Gids: Array<string>) {
|
||||
async getGroupFileCount(Gids: Array<string>) {
|
||||
return this.context.session.getRichMediaService().batchGetGroupFileCount(Gids);
|
||||
}
|
||||
|
||||
async getGroupIgnoreNotifies() {
|
||||
}
|
||||
|
||||
async getArkJsonGroupShare(GroupCode: string) {
|
||||
const ret = await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
|
||||
@@ -471,19 +375,12 @@ export class NTQQGroupApi {
|
||||
return this.context.session.getGroupService().modifyGroupName(groupQQ, groupName, false);
|
||||
}
|
||||
|
||||
// 头衔不可用
|
||||
/*
|
||||
async setGroupTitle(groupQQ: string, uid: string, title: string) {
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
async publishGroupBulletin(groupQQ: string, content: string, picInfo: {
|
||||
id: string,
|
||||
width: number,
|
||||
height: number
|
||||
} | undefined = undefined, pinned: number = 0, confirmRequired: number = 0) {
|
||||
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');
|
||||
//text是content内容url编码
|
||||
const data = {
|
||||
text: encodeURI(content),
|
||||
@@ -492,7 +389,7 @@ export class NTQQGroupApi {
|
||||
pinned: pinned,
|
||||
confirmRequired: confirmRequired,
|
||||
};
|
||||
return this.context.session.getGroupService().publishGroupBulletin(groupQQ, _Pskey!, data);
|
||||
return this.context.session.getGroupService().publishGroupBulletin(groupQQ, psKey!, data);
|
||||
}
|
||||
|
||||
async getGroupRemainAtTimes(GroupCode: string) {
|
||||
|
@@ -5,4 +5,5 @@ export * from './msg';
|
||||
export * from './user';
|
||||
export * from './webapi';
|
||||
export * from './sign';
|
||||
export * from './system';
|
||||
export * from './system';
|
||||
export * from './cache';
|
||||
|
@@ -14,12 +14,15 @@ export class NTQQMsgApi {
|
||||
this.context = context;
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async getAioFirstViewLatestMsgs(peer: Peer, MsgCount: number) {
|
||||
return this.context.session.getMsgService().getAioFirstViewLatestMsgs(peer, MsgCount);
|
||||
}
|
||||
|
||||
async getLatestDbMsgs(peer: Peer, MsgCount: number) {
|
||||
return this.context.session.getMsgService().getLatestDbMsgs(peer, MsgCount);
|
||||
}
|
||||
|
||||
async FetchLongMsg(peer: Peer, msgId: string) {
|
||||
return this.context.session.getMsgService().fetchLongMsg(peer, msgId);
|
||||
}
|
||||
@@ -29,19 +32,10 @@ export class NTQQMsgApi {
|
||||
}
|
||||
|
||||
async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
||||
//console.log(peer, msgSeq, emojiId, emojiType, count);
|
||||
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa
|
||||
return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, count);
|
||||
}
|
||||
|
||||
// napCatCore: NapCatCore | null = null;
|
||||
// enum BaseEmojiType {
|
||||
// NORMAL_EMOJI,
|
||||
// SUPER_EMOJI,
|
||||
// RANDOM_SUPER_EMOJI,
|
||||
// CHAIN_SUPER_EMOJI,
|
||||
// EMOJI_EMOJI
|
||||
// }
|
||||
async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) {
|
||||
// nt_qq//global//nt_data//Emoji//emoji-resource//sysface_res/apng/ 下可以看到所有QQ表情预览
|
||||
// nt_qq\global\nt_data\Emoji\emoji-resource\face_config.json 里面有所有表情的id, 自带表情id是QSid, 标准emoji表情id是QCid
|
||||
@@ -60,23 +54,10 @@ export class NTQQMsgApi {
|
||||
return this.context.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map());
|
||||
}
|
||||
|
||||
async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||
chatInfo: peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: [],
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: isReverseOrder,//此参数有点离谱 注意不是本次查询的排序 而是全部消历史信息的排序 默认false 从新消息拉取到旧消息
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: count,
|
||||
});
|
||||
}
|
||||
|
||||
async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) {
|
||||
if (!peer) throw new Error('peer is not allowed');
|
||||
if (!msgIds) throw new Error('msgIds is not allowed');
|
||||
//Mlikiowa: 参数不合规会导致NC异常崩溃 原因是TX未对进入参数判断 对应Android标记@NotNull AndroidJADX分析可得
|
||||
//MliKiowa: 参数不合规会导致NC异常崩溃 原因是TX未对进入参数判断 对应Android标记@NotNull AndroidJADX分析可得
|
||||
return await this.context.session.getMsgService().getMsgsByMsgId(peer, msgIds);
|
||||
}
|
||||
|
||||
@@ -90,7 +71,7 @@ export class NTQQMsgApi {
|
||||
|
||||
async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) {
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||
chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa
|
||||
chatInfo: peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: [],
|
||||
filterMsgToTime: '0',
|
||||
@@ -100,11 +81,41 @@ export class NTQQMsgApi {
|
||||
pageLimit: 1,
|
||||
});
|
||||
}
|
||||
|
||||
async queryMsgsWithFilterExWithSeqV2(peer: Peer, msgSeq: string, MsgTime: string, SendersUid: string[]) {
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||
chatInfo: peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: SendersUid,
|
||||
filterMsgToTime: MsgTime,
|
||||
filterMsgFromTime: MsgTime,
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
}
|
||||
async queryFirstMsgBySeq(peer: Peer, msgSeq: string) {
|
||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||
chatInfo: peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: [],
|
||||
filterMsgToTime: '0',
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: true,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
});
|
||||
}
|
||||
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||
}
|
||||
|
||||
async getMsgBySeqList(peer: Peer, msgSeqList: string[]) {
|
||||
//坏的
|
||||
return await this.context.session.getMsgService().getMsgsBySeqList(peer, msgSeqList);
|
||||
}
|
||||
async getMsgBySeqExFirstMsg(peer: Peer, rootMsgId: string, replyMsgId: string) {
|
||||
let reply = await this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, rootMsgId, replyMsgId);
|
||||
console.log(reply);
|
||||
}
|
||||
async getMsgExBySeq(peer: Peer, msgSeq: string) {
|
||||
const DateNow = Math.floor(Date.now() / 1000);
|
||||
const filterMsgFromTime = (DateNow - 300).toString();
|
||||
@@ -134,10 +145,7 @@ export class NTQQMsgApi {
|
||||
params,
|
||||
],
|
||||
() => true,
|
||||
( /* groupFileListResult: GroupFileInfoUpdateParamType */) => {
|
||||
//Developer Mlikiowa Todo: 此处有问题 无法判断是否成功
|
||||
return true;
|
||||
},
|
||||
() => true, // Todo: 应当通过 groupFileListResult 判断
|
||||
1,
|
||||
5000,
|
||||
);
|
||||
@@ -157,14 +165,6 @@ export class NTQQMsgApi {
|
||||
}
|
||||
|
||||
async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) {
|
||||
//By Jadx/Ida Mlikiowa
|
||||
const TempGameSession = {
|
||||
nickname: '',
|
||||
gameAppId: '',
|
||||
selfTinyId: '',
|
||||
peerRoleId: '',
|
||||
peerOpenId: '',
|
||||
};
|
||||
return this.context.session.getMsgService().prepareTempChat({
|
||||
chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP,
|
||||
peerUid: toUserUid,
|
||||
@@ -173,7 +173,13 @@ export class NTQQMsgApi {
|
||||
sig: '',
|
||||
selfPhone: '',
|
||||
selfUid: this.core.selfInfo.uid,
|
||||
gameSession: TempGameSession,
|
||||
gameSession: {
|
||||
nickname: '',
|
||||
gameAppId: '',
|
||||
selfTinyId: '',
|
||||
peerRoleId: '',
|
||||
peerOpenId: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,7 +188,7 @@ export class NTQQMsgApi {
|
||||
}
|
||||
|
||||
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
//唉? !我有个想法
|
||||
//唉?!我有个想法
|
||||
if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') {
|
||||
const member = await this.core.apis.GroupApi.getGroupMember(peer.guildId, peer.peerUid!);
|
||||
if (member) {
|
||||
@@ -212,11 +218,7 @@ export class NTQQMsgApi {
|
||||
1,
|
||||
timeout,
|
||||
);
|
||||
return msgList.find(msgRecord => {
|
||||
if (msgRecord.guildId === msgId) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return msgList.find(msgRecord => msgRecord.guildId === msgId);
|
||||
}
|
||||
|
||||
async generateMsgUniqueId(chatType: number, time: string) {
|
||||
@@ -246,14 +248,10 @@ export class NTQQMsgApi {
|
||||
new Map(),
|
||||
],
|
||||
() => true,
|
||||
(msgRecords) => {
|
||||
for (const msgRecord of msgRecords) {
|
||||
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
(msgRecords) => msgRecords.some(
|
||||
msgRecord => msgRecord.peerUid === destPeer.peerUid
|
||||
&& msgRecord.senderUid === this.core.selfInfo.uid
|
||||
),
|
||||
);
|
||||
for (const msg of msgList) {
|
||||
const arkElement = msg.elements.find(ele => ele.arkElement);
|
||||
@@ -271,7 +269,7 @@ export class NTQQMsgApi {
|
||||
throw new Error('转发消息超时');
|
||||
}
|
||||
|
||||
async markallMsgAsRead() {
|
||||
async markAllMsgAsRead() {
|
||||
return this.context.session.getMsgService().setAllC2CAndGroupMsgRead();
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ export class NTQQSystemApi {
|
||||
return this.core.util.hasOtherRunningQQProcess();
|
||||
}
|
||||
|
||||
async ORCImage(filePath: string) {
|
||||
async ocrImage(filePath: string) {
|
||||
return this.context.session.getNodeMiscService().wantWinScreenOCR(filePath);
|
||||
}
|
||||
|
||||
@@ -21,20 +21,16 @@ export class NTQQSystemApi {
|
||||
return this.context.session.getRichMediaService().translateEnWordToZn(words);
|
||||
}
|
||||
|
||||
//调用会超时 没灯用 (好像是通知listener的) onLineDev
|
||||
async getOnlineDev() {
|
||||
return this.context.session.getMsgService().getOnLineDev();
|
||||
}
|
||||
|
||||
//1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50
|
||||
async getArkJsonCollection(cid: string) {
|
||||
return await this.core.eventWrapper.callNoListenerEvent('NodeIKernelCollectionService/collectionArkShare', '1717662698058');
|
||||
}
|
||||
|
||||
async BootMiniApp(appfile: string, params: string) {
|
||||
async bootMiniApp(appFile: string, params: string) {
|
||||
await this.context.session.getNodeMiscService().setMiniAppVersion('2.16.4');
|
||||
// const c = await this.context.session.getNodeMiscService().getMiniAppPath();
|
||||
|
||||
return this.context.session.getNodeMiscService().startNewMiniApp(appfile, params);
|
||||
return this.context.session.getNodeMiscService().startNewMiniApp(appFile, params);
|
||||
}
|
||||
}
|
||||
|
@@ -15,9 +15,7 @@ export class NTQQUserApi {
|
||||
|
||||
async getProfileLike(uid: string) {
|
||||
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
||||
friendUids: [
|
||||
uid,
|
||||
],
|
||||
friendUids: [uid],
|
||||
basic: 1,
|
||||
vote: 1,
|
||||
favorite: 0,
|
||||
@@ -63,41 +61,6 @@ export class NTQQUserApi {
|
||||
return this.context.session.getGroupService().setHeader(gc, filePath);
|
||||
}
|
||||
|
||||
async fetchUserDetailInfos(uids: string[]) {
|
||||
// TODO: 26702 以上使用新接口 .Dev MliKiowa
|
||||
const retData: User[] = [];
|
||||
const [_retData, _retListener] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelProfileService/fetchUserDetailInfo',
|
||||
'NodeIKernelProfileListener/onUserDetailInfoChanged',
|
||||
[
|
||||
'BuddyProfileStore',
|
||||
uids,
|
||||
UserDetailSource.KSERVER,
|
||||
[ProfileBizType.KALL],
|
||||
],
|
||||
() => true,
|
||||
(profile) => {
|
||||
if (uids.includes(profile.uid)) {
|
||||
const RetUser: User = {
|
||||
...profile.simpleInfo.coreInfo,
|
||||
...profile.simpleInfo.status,
|
||||
...profile.simpleInfo.vasInfo,
|
||||
...profile.commonExt,
|
||||
...profile.simpleInfo.baseInfo,
|
||||
qqLevel: profile.commonExt.qqLevel,
|
||||
pendantId: '',
|
||||
};
|
||||
retData.push(RetUser);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
uids.length,
|
||||
);
|
||||
|
||||
return retData;
|
||||
}
|
||||
|
||||
async fetchUserDetailInfo(uid: string, mode: UserDetailSource = UserDetailSource.KDB) {
|
||||
const [_retData, profile] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelProfileService/fetchUserDetailInfo',
|
||||
@@ -112,7 +75,6 @@ export class NTQQUserApi {
|
||||
(profile) => profile.uid === uid,
|
||||
);
|
||||
const RetUser: User = {
|
||||
...profile.simpleInfo.coreInfo,
|
||||
...profile.simpleInfo.status,
|
||||
...profile.simpleInfo.vasInfo,
|
||||
...profile.commonExt,
|
||||
@@ -120,17 +82,22 @@ export class NTQQUserApi {
|
||||
qqLevel: profile.commonExt?.qqLevel,
|
||||
age: profile.simpleInfo.baseInfo.age,
|
||||
pendantId: '',
|
||||
...profile.simpleInfo.coreInfo
|
||||
};
|
||||
return RetUser;
|
||||
}
|
||||
|
||||
async getUserDetailInfo(uid: string): Promise<User> {
|
||||
const retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
|
||||
let retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
|
||||
if (retUser && retUser.uin !== '0') {
|
||||
return retUser;
|
||||
}
|
||||
this.context.logger.logDebug('[NapCat] [Mark] getUserDetailInfo Mode1 Failed.');
|
||||
return this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER);
|
||||
retUser = await this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER);
|
||||
if (retUser && retUser.uin === '0') {
|
||||
retUser.uin = await this.core.apis.UserApi.getUidByUinV2(uid) ?? '0';
|
||||
}
|
||||
return retUser;
|
||||
}
|
||||
|
||||
async modifySelfProfile(param: ModifyProfileParams) {
|
||||
@@ -156,7 +123,6 @@ export class NTQQUserApi {
|
||||
version: 0,
|
||||
aioKeywordVersion: 0,
|
||||
});
|
||||
// console.log(robotUinRanges?.response?.robotUinRanges);
|
||||
return robotUinRanges?.response?.robotUinRanges;
|
||||
}
|
||||
|
||||
@@ -170,7 +136,7 @@ export class NTQQUserApi {
|
||||
|
||||
//需要异常处理
|
||||
|
||||
async getSkey(): Promise<string | undefined> {
|
||||
async getSKey(): Promise<string | undefined> {
|
||||
const ClientKeyData = await this.forceFetchClientKey();
|
||||
if (ClientKeyData.result !== 0) {
|
||||
throw new Error('getClientKey Error');
|
||||
@@ -181,7 +147,7 @@ export class NTQQUserApi {
|
||||
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
|
||||
const skey = cookies['skey'];
|
||||
if (!skey) {
|
||||
throw new Error('getSkey Skey is Empty');
|
||||
throw new Error('SKey is Empty');
|
||||
}
|
||||
return skey;
|
||||
}
|
||||
@@ -194,8 +160,8 @@ export class NTQQUserApi {
|
||||
if (uid) return uid;
|
||||
uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
|
||||
if (uid) return uid;
|
||||
const unveifyUid = (await this.getUserDetailInfoByUinV2(Uin)).detail.uid;//从QQ Native 特殊转换
|
||||
if (unveifyUid.indexOf('*') == -1) uid = unveifyUid;
|
||||
const unverifiedUid = (await this.getUserDetailInfoByUinV2(Uin)).detail.uid;//从QQ Native 特殊转换
|
||||
if (unverifiedUid.indexOf('*') == -1) uid = unverifiedUid;
|
||||
//if (uid) return uid;
|
||||
return uid;
|
||||
}
|
||||
@@ -231,7 +197,10 @@ export class NTQQUserApi {
|
||||
}
|
||||
|
||||
async getUserDetailInfoByUinV2(Uin: string) {
|
||||
return await this.core.eventWrapper.callNoListenerEvent('NodeIKernelProfileService/getUserDetailInfoByUin', Uin);
|
||||
return await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||
Uin
|
||||
);
|
||||
}
|
||||
|
||||
async forceFetchClientKey() {
|
||||
|
@@ -26,8 +26,7 @@ export class NTQQWebApi {
|
||||
msg_seq: msgSeq,
|
||||
msg_random: msgRandom,
|
||||
target_group_code: targetGroupCode,
|
||||
}).toString()
|
||||
}`;
|
||||
}).toString()}`;
|
||||
try {
|
||||
return RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
} catch (e) {
|
||||
@@ -35,16 +34,12 @@ export class NTQQWebApi {
|
||||
}
|
||||
}
|
||||
async getGroupEssenceMsgAll(GroupCode: string) {
|
||||
let ret: GroupEssenceMsgRet[] = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let data = await this.getGroupEssenceMsg(GroupCode, i, 50);
|
||||
const ret: GroupEssenceMsgRet[] = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const data = await this.getGroupEssenceMsg(GroupCode, i, 50);
|
||||
if (!data) break;
|
||||
if (data.data.is_end) {
|
||||
ret.push(data);
|
||||
break;
|
||||
}
|
||||
ret.push(data);
|
||||
|
||||
if (data.data.is_end) break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -55,19 +50,18 @@ export class NTQQWebApi {
|
||||
page_start: page_start.toString(),
|
||||
page_limit: page_limit.toString(),
|
||||
group_code: GroupCode,
|
||||
}).toString()
|
||||
}`;
|
||||
let ret;
|
||||
}).toString()}`;
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>
|
||||
(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
const ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>(
|
||||
url,
|
||||
'GET',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
return ret.retcode === 0 ? ret : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
if (ret.retcode !== 0) {
|
||||
return undefined;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
||||
@@ -75,15 +69,18 @@ export class NTQQWebApi {
|
||||
const memberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
const retList: Promise<WebApiGroupMemberRet>[] = [];
|
||||
const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet>
|
||||
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
|
||||
const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet>(
|
||||
`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
|
||||
st: '0',
|
||||
end: '40',
|
||||
sort: '1',
|
||||
gc: GroupCode,
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
}).toString()
|
||||
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
}).toString()}`,
|
||||
'POST',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) {
|
||||
return [];
|
||||
} else {
|
||||
@@ -95,15 +92,18 @@ export class NTQQWebApi {
|
||||
const PageNum = Math.ceil(fastRet.count / 40);
|
||||
//遍历批量请求
|
||||
for (let i = 2; i <= PageNum; i++) {
|
||||
const ret = RequestUtil.HttpGetJson<WebApiGroupMemberRet>
|
||||
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
|
||||
const ret = RequestUtil.HttpGetJson<WebApiGroupMemberRet>(
|
||||
`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
|
||||
st: ((i - 1) * 40).toString(),
|
||||
end: (i * 40).toString(),
|
||||
sort: '1',
|
||||
gc: GroupCode,
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
}).toString()
|
||||
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
}).toString()}`,
|
||||
'POST',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
retList.push(ret);
|
||||
}
|
||||
//批量等待
|
||||
@@ -131,20 +131,56 @@ export class NTQQWebApi {
|
||||
// return await res.json();
|
||||
// }
|
||||
|
||||
async setGroupNotice(GroupCode: string, Content: string) {
|
||||
async setGroupNotice(
|
||||
GroupCode: string,
|
||||
Content: string,
|
||||
pinned: number = 0,
|
||||
type: number = 1,
|
||||
is_show_edit_card: number = 1,
|
||||
tip_window_type: number = 1,
|
||||
confirm_required: number = 1,
|
||||
picId: string = '',
|
||||
imgWidth: number = 540,
|
||||
imgHeight: number = 300,
|
||||
) {
|
||||
interface SetNoticeRetSuccess {
|
||||
ec: number;
|
||||
em: string;
|
||||
id: number;
|
||||
ltsm: number;
|
||||
new_fid: string;
|
||||
read_only: number;
|
||||
role: number;
|
||||
srv_code: number;
|
||||
}
|
||||
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
let ret: any = undefined;
|
||||
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<any>
|
||||
(`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({
|
||||
let settings = JSON.stringify({
|
||||
is_show_edit_card: is_show_edit_card,
|
||||
tip_window_type: tip_window_type,
|
||||
confirm_required: confirm_required
|
||||
});
|
||||
const externalParam = {
|
||||
pic: picId,
|
||||
imgWidth: imgWidth.toString(),
|
||||
imgHeight: imgHeight.toString(),
|
||||
};
|
||||
let ret: SetNoticeRetSuccess = await RequestUtil.HttpGetJson<SetNoticeRetSuccess>(
|
||||
`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?${new URLSearchParams({
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
qid: GroupCode,
|
||||
text: Content,
|
||||
pinned: '0',
|
||||
type: '1',
|
||||
settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}',
|
||||
}).toString()
|
||||
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
pinned: pinned.toString(),
|
||||
type: type.toString(),
|
||||
settings: settings,
|
||||
...(picId === '' ? {} : externalParam)
|
||||
}).toString()}`,
|
||||
'POST',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
return ret;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
@@ -153,16 +189,24 @@ export class NTQQWebApi {
|
||||
|
||||
async getGroupNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
let ret: WebApiGroupNoticeRet | undefined = undefined;
|
||||
try {
|
||||
const url = 'https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=' +
|
||||
this.getBknFromCookie(cookieObject) + '&qid=' + GroupCode + '&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20';
|
||||
|
||||
ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
if (ret?.ec !== 0) {
|
||||
return undefined;
|
||||
}
|
||||
return ret;
|
||||
const ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(
|
||||
`https://web.qun.qq.com/cgi-bin/announce/get_t_list?${new URLSearchParams({
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
qid: GroupCode,
|
||||
ft: '23',
|
||||
ni: '1',
|
||||
n: '1',
|
||||
i: '1',
|
||||
log_read: '1',
|
||||
platform: '1',
|
||||
s: '-1',
|
||||
}).toString()}&n=20`,
|
||||
'GET',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
return ret?.ec === 0 ? ret : undefined;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -171,14 +215,17 @@ export class NTQQWebApi {
|
||||
async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => {
|
||||
const url = `https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
|
||||
gc: Internal_groupCode,
|
||||
type: Internal_type.toString(),
|
||||
}).toString()
|
||||
}`;
|
||||
let resJson;
|
||||
try {
|
||||
const res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
|
||||
const res = await RequestUtil.HttpGetText(
|
||||
`https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
|
||||
gc: Internal_groupCode,
|
||||
type: Internal_type.toString(),
|
||||
}).toString()}`,
|
||||
'GET',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
const match = /window\.__INITIAL_STATE__=(.*?);/.exec(res);
|
||||
if (match) {
|
||||
resJson = JSON.parse(match[1].trim());
|
||||
@@ -189,7 +236,7 @@ export class NTQQWebApi {
|
||||
return resJson?.actorList;
|
||||
}
|
||||
} catch (e) {
|
||||
this.context.logger.logDebug('获取当前群荣耀失败', url, e);
|
||||
this.context.logger.logDebug('获取当前群荣耀失败', e);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -268,10 +315,12 @@ export class NTQQWebApi {
|
||||
this.context.logger.logError('获取快乐源泉失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 冒尖小春笋好像已经被tx扬了 R.I.P.
|
||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||
HonorInfo.strong_newbie_list = [];
|
||||
}
|
||||
|
||||
return HonorInfo;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ export interface GetFileListParam {
|
||||
startIndex: number;
|
||||
sortOrder: number;
|
||||
showOnlinedocFolder: number;
|
||||
folderId?: string;
|
||||
}
|
||||
|
||||
export enum ElementType {
|
||||
@@ -369,7 +370,8 @@ export interface ReplyElement {
|
||||
replayMsgSeq: string;
|
||||
replayMsgId: string;
|
||||
senderUin: string;
|
||||
senderUinStr: string;
|
||||
senderUidStr?: string;
|
||||
replyMsgTime?: string;
|
||||
}
|
||||
|
||||
export interface SendReplyElement {
|
||||
|
38
src/core/external/appid.json
vendored
38
src/core/external/appid.json
vendored
@@ -1,34 +1,14 @@
|
||||
{
|
||||
"3.2.12-27187": {
|
||||
"appid": 537240645,
|
||||
"qua": "V1_LNX_NQ_3.2.12_27187_GW_B"
|
||||
"3.2.12-27597": {
|
||||
"appid": 537243600,
|
||||
"qua": "V1_LNX_NQ_3.2.12_27597_GW_B"
|
||||
},
|
||||
"3.2.12-27206": {
|
||||
"appid": 537240645,
|
||||
"qua": "V1_LNX_NQ_3.2.12_27206_GW_B"
|
||||
"9.9.15-27597": {
|
||||
"appid": 537243441,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27597_GW_B"
|
||||
},
|
||||
"3.2.12-27254": {
|
||||
"appid": 537240795,
|
||||
"qua": "V1_LNX_NQ_3.2.12_27254_GW_B"
|
||||
},
|
||||
"9.9.15-27187": {
|
||||
"appid": 537240610,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27187_GW_B"
|
||||
},
|
||||
"9.9.15-27206": {
|
||||
"appid": 537240610,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27206_GW_B"
|
||||
},
|
||||
"9.9.15-27254": {
|
||||
"appid": 537240709,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27254_GW_B"
|
||||
},
|
||||
"9.9.15-27333": {
|
||||
"appid": 537240709,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27333_GW_B"
|
||||
},
|
||||
"9.9.15-27391": {
|
||||
"appid": 537240709,
|
||||
"qua": "V1_WIN_NQ_9.9.15_27333_GW_B"
|
||||
"6.9.53-27597": {
|
||||
"appid": 537243538,
|
||||
"qua": "V1_MAC_NQ_6.9.53_27597_GW_B"
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { getMachineId, hostname, systemName, systemVersion } from '@/common/system';
|
||||
import { NTEventWrapper } from '@/common/event';
|
||||
import { DataSource, GroupMember, SelfInfo } from '@/core/entities';
|
||||
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/entities';
|
||||
import { NapCatConfigLoader } from '@/core/helper/config';
|
||||
import os from 'node:os';
|
||||
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
|
||||
@@ -42,9 +42,15 @@ export enum NapCatCoreWorkingEnv {
|
||||
}
|
||||
|
||||
export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
||||
let wrapperNodePath = path.resolve(path.dirname(process.execPath), './resources/app/wrapper.node');
|
||||
let appPath;
|
||||
if (os.platform() === 'darwin') {
|
||||
appPath = path.resolve(path.dirname(process.execPath), '../Resources/app');
|
||||
} else {
|
||||
appPath = path.resolve(path.dirname(process.execPath), './resources/app');
|
||||
}
|
||||
let wrapperNodePath = path.resolve(appPath, 'wrapper.node');
|
||||
if (!fs.existsSync(wrapperNodePath)) {
|
||||
wrapperNodePath = path.join(path.dirname(process.execPath), `resources/app/versions/${QQVersion}/wrapper.node`);
|
||||
wrapperNodePath = path.join(appPath, `versions/${QQVersion}/wrapper.node`);
|
||||
}
|
||||
const nativemodule: any = { exports: {} };
|
||||
process.dlopen(nativemodule, wrapperNodePath);
|
||||
@@ -113,6 +119,11 @@ export class NapCatCore {
|
||||
// Renamed from 'InitDataListener'
|
||||
async initNapCatCoreListeners() {
|
||||
const msgListener = new NodeIKernelMsgListener();
|
||||
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
|
||||
// 下线通知
|
||||
this.context.logger.logError('[KickedOffLine] [' + Info.tipsTitle + '] ' + Info.tipsDesc);
|
||||
this.selfInfo.online = false;
|
||||
};
|
||||
msgListener.onRecvMsg = (msgs) => {
|
||||
msgs.forEach(msg => this.context.logger.logMessage(msg, this.selfInfo));
|
||||
};
|
||||
@@ -130,10 +141,12 @@ export class NapCatCore {
|
||||
Object.assign(this.selfInfo, profile);
|
||||
}
|
||||
};
|
||||
profileListener.onSelfStatusChanged = (/* Info: SelfStatusInfo */) => {
|
||||
// if (Info.status == 20) {
|
||||
// log("账号状态变更为离线")
|
||||
// }
|
||||
profileListener.onSelfStatusChanged = (Info: SelfStatusInfo) => {
|
||||
if (Info.status == 20) {
|
||||
this.selfInfo.online = false;
|
||||
this.context.logger.log("账号状态变更为离线");
|
||||
}
|
||||
this.selfInfo.online = true;
|
||||
};
|
||||
this.context.session.getProfileService().addKernelProfileListener(
|
||||
proxiedListenerOf(profileListener, this.context.logger),
|
||||
|
@@ -25,7 +25,7 @@ export class NodeIKernelFileAssistantListener {
|
||||
|
||||
export type SearchResultWrapper = {
|
||||
searchId: number,
|
||||
resultType: number,
|
||||
resultId: number,
|
||||
hasMore: boolean,
|
||||
resultItems: SearchResultItem[],
|
||||
};
|
||||
|
@@ -29,7 +29,47 @@ export interface GroupFileInfoUpdateParamType {
|
||||
retMsg: string;
|
||||
clientWording: string;
|
||||
isEnd: boolean;
|
||||
item: Array<any>;
|
||||
item: Array<{
|
||||
peerId: string;
|
||||
type: number;
|
||||
folderInfo?: {
|
||||
folderId: string;
|
||||
parentFolderId: string;
|
||||
folderName: string;
|
||||
createTime: number;
|
||||
modifyTime: number;
|
||||
createUin: string;
|
||||
creatorName: string;
|
||||
totalFileCount: number;
|
||||
modifyUin: string;
|
||||
modifyName: string;
|
||||
usedSpace: string;
|
||||
},
|
||||
fileInfo?: {
|
||||
fileModelId: string;
|
||||
fileId: string;
|
||||
fileName: string;
|
||||
fileSize: string;
|
||||
busId: number;
|
||||
uploadedSize: string;
|
||||
uploadTime: number;
|
||||
deadTime: number;
|
||||
modifyTime: number;
|
||||
downloadTimes: number;
|
||||
sha: string;
|
||||
sha3: string;
|
||||
md5: string;
|
||||
uploaderLocalPath: string;
|
||||
uploaderName: string;
|
||||
uploaderUin: string;
|
||||
parentFolderId: string;
|
||||
localPath: string;
|
||||
transStatus: number;
|
||||
transType: number;
|
||||
elementId: string;
|
||||
isFolder: boolean;
|
||||
},
|
||||
}>;
|
||||
allFileCount: string;
|
||||
nextIndex: string;
|
||||
reqId: string;
|
||||
|
@@ -1,15 +1,15 @@
|
||||
// @generated by protobuf-ts 2.9.4
|
||||
// @generated from protobuf file "EmojiLikeToOthers.proto" (package "SysMessage", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
import type {
|
||||
BinaryReadOptions,
|
||||
BinaryWriteOptions,
|
||||
IBinaryReader,
|
||||
IBinaryWriter,
|
||||
PartialMessage,
|
||||
} from '@protobuf-ts/runtime';
|
||||
import { MessageType, reflectionMergePartial, UnknownFieldHandler, WireType } from '@protobuf-ts/runtime';
|
||||
|
||||
/**
|
||||
* @generated from protobuf message SysMessage.EmojiLikeToOthersWrapper1
|
||||
*/
|
||||
|
@@ -1,15 +1,15 @@
|
||||
// @generated by protobuf-ts 2.9.4
|
||||
// @generated from protobuf file "GreyTipWrapper.proto" (package "SysMessage", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
import type {
|
||||
BinaryReadOptions,
|
||||
BinaryWriteOptions,
|
||||
IBinaryReader,
|
||||
IBinaryWriter,
|
||||
PartialMessage,
|
||||
} from '@protobuf-ts/runtime';
|
||||
import { MessageType, reflectionMergePartial, UnknownFieldHandler, WireType } from '@protobuf-ts/runtime';
|
||||
|
||||
/**
|
||||
* @generated from protobuf message SysMessage.GreyTipWrapper
|
||||
*/
|
||||
|
@@ -1,15 +1,15 @@
|
||||
// @generated by protobuf-ts 2.9.4
|
||||
// @generated from protobuf file "SysMessage.proto" (package "SysMessage", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
import type {
|
||||
BinaryReadOptions,
|
||||
BinaryWriteOptions,
|
||||
IBinaryReader,
|
||||
IBinaryWriter,
|
||||
PartialMessage,
|
||||
} from '@protobuf-ts/runtime';
|
||||
import { MessageType, reflectionMergePartial, UnknownFieldHandler, WireType } from '@protobuf-ts/runtime';
|
||||
|
||||
/**
|
||||
* @generated from protobuf message SysMessage.SysMessage
|
||||
*/
|
||||
|
@@ -11,7 +11,7 @@ export interface NodeIKernelFileAssistantService {
|
||||
|
||||
getFileSessionList(): unknown;
|
||||
|
||||
searchFile(keywords: string[], params: { resultType: number, pageLimit: number }): unknown;
|
||||
searchFile(keywords: string[], params: { resultType: number, pageLimit: number }, resultId: number): number;
|
||||
|
||||
resetSearchFileSortType(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
|
@@ -155,7 +155,7 @@ export interface NodeIKernelRichMediaService {
|
||||
}): unknown;
|
||||
|
||||
//arg3为“”
|
||||
downloadFileForModelId(peer: Peer, ModelId: string[]): Promise<unknown>;
|
||||
downloadFileForModelId(peer: Peer, ModelId: string[], unknown: string): Promise<unknown>;
|
||||
|
||||
//第三个参数 Array<Type>
|
||||
// this.fileId = "";
|
||||
|
@@ -2,8 +2,7 @@ import { NapCatPathWrapper } from '@/common/path';
|
||||
import { LogWrapper } from '@/common/log';
|
||||
import { proxiedListenerOf } from '@/common/proxy-handler';
|
||||
import { QQBasicInfoWrapper } from '@/common/qq-basic-info';
|
||||
import { loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from '@/core';
|
||||
import { InstanceContext } from '@/core';
|
||||
import { InstanceContext, loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from '@/core';
|
||||
import { SelfInfo } from '@/core/entities';
|
||||
import { NodeIKernelLoginListener } from '@/core/listeners';
|
||||
import { NodeIKernelLoginService } from '@/core/services';
|
||||
|
@@ -1,4 +0,0 @@
|
||||
# nekodoge
|
||||
此协议为替代QQ平台 OnebotV11长期不可靠问题
|
||||
|
||||
# 规划路线
|
@@ -1,18 +0,0 @@
|
||||
import { createServer } from 'node:net';
|
||||
export class NewAdapterNetwork {
|
||||
constructor(public host: number, public port: number) { }
|
||||
async open() {
|
||||
const server = createServer((socket) => {
|
||||
socket.on('data', (data) => {
|
||||
|
||||
});
|
||||
socket.on('end', () => {
|
||||
|
||||
});
|
||||
socket.on('connect', () => {
|
||||
|
||||
})
|
||||
});
|
||||
server.listen(this.port, this.host);
|
||||
}
|
||||
}
|
@@ -54,7 +54,7 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
|
||||
public async websocketHandle(payload: PayloadType, echo: any): Promise<OB11Return<ReturnDataType | null>> {
|
||||
const result = await this.check(payload);
|
||||
if (!result.valid) {
|
||||
return OB11Response.error(result.message, 1400);
|
||||
return OB11Response.error(result.message, 1400, echo);
|
||||
}
|
||||
try {
|
||||
const resData = await this._handle(payload);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { OB11Return } from '../types';
|
||||
|
||||
import { isNull } from '../../common/helper';
|
||||
import { isNull } from '@/common/helper';
|
||||
|
||||
export class OB11Response {
|
||||
static res<T>(data: T, status: string, retcode: number, message: string = ''): OB11Return<T> {
|
||||
|
@@ -24,10 +24,9 @@ export class FetchEmojiLike extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||
if (!msgIdPeer) throw new Error('消息不存在');
|
||||
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
|
||||
return await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, +(payload.count ?? 20));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ export class GetCollectionList extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQCollectionApi = this.core.apis.CollectionApi;
|
||||
return await NTQQCollectionApi.getAllCollection(parseInt(payload.category.toString()), +(payload.count ?? 1));
|
||||
return await this.core.apis.CollectionApi.getAllCollection(parseInt(payload.category.toString()), +(payload.count ?? 1));
|
||||
}
|
||||
}
|
||||
|
@@ -17,8 +17,6 @@ export class GetGroupInfoEx extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const groupInfoEx = (await NTQQGroupApi.getGroupExtFE0Info([payload.group_id.toString()])).result.groupExtInfos.get(payload.group_id.toString());
|
||||
return groupInfoEx;
|
||||
return (await this.core.apis.GroupApi.getGroupExtFE0Info([payload.group_id.toString()])).result.groupExtInfos.get(payload.group_id.toString());
|
||||
}
|
||||
}
|
||||
|
@@ -5,11 +5,10 @@ export class GetProfileLike extends BaseAction<void, any> {
|
||||
actionName = ActionName.GetProfileLike;
|
||||
|
||||
async _handle(payload: void) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const ret = await NTQQUserApi.getProfileLike(this.core.selfInfo.uid);
|
||||
const ret = await this.core.apis.UserApi.getProfileLike(this.core.selfInfo.uid);
|
||||
const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos;
|
||||
for (let i = 0; i < listdata.length; i++) {
|
||||
listdata[i].uin = parseInt((await NTQQUserApi.getUinByUidV2(listdata[i].uid)) || '');
|
||||
listdata[i].uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(listdata[i].uid)) || '');
|
||||
}
|
||||
return listdata;
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ export class GetRobotUinRange extends BaseAction<void, Array<any>> {
|
||||
actionName = ActionName.GetRobotUinRange;
|
||||
|
||||
async _handle(payload: void) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
return await NTQQUserApi.getRobotUinRange();
|
||||
return await this.core.apis.UserApi.getRobotUinRange();
|
||||
}
|
||||
}
|
||||
|
@@ -19,14 +19,13 @@ export class OCRImage extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQSystemApi = this.core.apis.SystemApi;
|
||||
const { path, isLocal, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
||||
if (!success) {
|
||||
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ret = await NTQQSystemApi.ORCImage(path);
|
||||
const ret = await this.core.apis.SystemApi.ocrImage(path);
|
||||
if (!isLocal) {
|
||||
fs.unlink(path, () => {
|
||||
});
|
||||
|
@@ -19,8 +19,6 @@ export class SetInputStatus extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.SetInputStatus;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
let peer: Peer;
|
||||
if (payload.group_id) {
|
||||
peer = {
|
||||
@@ -28,7 +26,7 @@ export class SetInputStatus extends BaseAction<Payload, any> {
|
||||
peerUid: payload.group_id,
|
||||
};
|
||||
} else if (payload.user_id) {
|
||||
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id);
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id);
|
||||
if (!uid) throw new Error('uid is empty');
|
||||
peer = {
|
||||
chatType: ChatType.KCHATTYPEC2C,
|
||||
@@ -38,6 +36,6 @@ export class SetInputStatus extends BaseAction<Payload, any> {
|
||||
throw new Error('请指定 group_id 或 user_id');
|
||||
}
|
||||
|
||||
return await NTQQMsgApi.sendShowInputStatusReq(peer, parseInt(payload.eventType));
|
||||
return await this.core.apis.MsgApi.sendShowInputStatusReq(peer, parseInt(payload.eventType));
|
||||
}
|
||||
}
|
||||
|
@@ -17,8 +17,6 @@ export class SetLongNick extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const ret = await NTQQUserApi.setLongNick(payload.longNick);
|
||||
return ret;
|
||||
return await this.core.apis.UserApi.setLongNick(payload.longNick);
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,10 @@ const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
status: { type: ['number', 'string'] },
|
||||
extStatus: { type: ['number', 'string'] },
|
||||
batteryStatus: { type: ['number', 'string'] },
|
||||
ext_status: { type: ['number', 'string'] },
|
||||
battery_status: { type: ['number', 'string'] },
|
||||
},
|
||||
required: ['status', 'extStatus', 'batteryStatus'],
|
||||
required: ['status', 'ext_status', 'battery_status'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
@@ -20,11 +20,10 @@ export class SetOnlineStatus extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const ret = await NTQQUserApi.setSelfOnlineStatus(
|
||||
const ret = await this.core.apis.UserApi.setSelfOnlineStatus(
|
||||
parseInt(payload.status.toString()),
|
||||
parseInt(payload.extStatus.toString()),
|
||||
parseInt(payload.batteryStatus.toString()),
|
||||
parseInt(payload.ext_status.toString()),
|
||||
parseInt(payload.battery_status.toString()),
|
||||
);
|
||||
if (ret.result !== 0) {
|
||||
throw new Error('设置在线状态失败');
|
||||
|
@@ -24,14 +24,13 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
||||
}
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const { path, isLocal, errMsg, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
const { path, isLocal, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ret = await NTQQUserApi.setQQAvatar(path);
|
||||
const ret = await this.core.apis.UserApi.setQQAvatar(path);
|
||||
if (!isLocal) {
|
||||
fs.unlink(path, () => {
|
||||
});
|
||||
|
@@ -19,12 +19,10 @@ export class SharePeer extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
if (payload.group_id) {
|
||||
return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id);
|
||||
return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id);
|
||||
} else if (payload.user_id) {
|
||||
return await NTQQUserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || '');
|
||||
return await this.core.apis.UserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || '');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +42,6 @@ export class ShareGroupEx extends BaseAction<PayloadGroupEx, any> {
|
||||
payloadSchema = SchemaDataGroupEx;
|
||||
|
||||
async _handle(payload: PayloadGroupEx) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
|
||||
return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id);
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,7 @@ export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null>
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQSystemApi = this.core.apis.SystemApi;
|
||||
const ret = await NTQQSystemApi.translateEnWordToZn(payload.words);
|
||||
const ret = await this.core.apis.SystemApi.translateEnWordToZn(payload.words);
|
||||
if (ret.result !== 0) {
|
||||
throw new Error('翻译失败');
|
||||
}
|
||||
|
@@ -2,8 +2,8 @@ import BaseAction from '../BaseAction';
|
||||
import fs from 'fs/promises';
|
||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||
import { ActionName } from '../types';
|
||||
import { ChatType, Peer, RawMessage } from '@/core/entities';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
|
||||
|
||||
export interface GetFilePayload {
|
||||
file: string; // 文件名或者fileUuid
|
||||
@@ -29,24 +29,32 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
payloadSchema: any = GetFileBase_PayloadSchema;
|
||||
|
||||
async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const NTQQFileApi = this.core.apis.FileApi;
|
||||
|
||||
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
|
||||
//接收消息标记模式
|
||||
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
|
||||
if (contextMsgFile) {
|
||||
const { peer, msgId, elementId } = contextMsgFile;
|
||||
const downloadPath = await NTQQFileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
||||
const mixElement = (await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
|
||||
.find(msg => msg.msgId === msgId)?.elements.find(e => e.elementId === elementId);
|
||||
const downloadPath = await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
||||
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
|
||||
.find(msg => msg.msgId === msgId);
|
||||
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
|
||||
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||
if (!mixElementInner) throw new Error('element not found');
|
||||
const fileSize = mixElementInner.fileSize?.toString() ?? '';
|
||||
const fileName = mixElementInner.fileName ?? '';
|
||||
|
||||
let url = '';
|
||||
if (mixElement?.picElement && rawMessage) {
|
||||
let tempData =
|
||||
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement) as OB11MessageImage | undefined;
|
||||
url = tempData?.data.url ?? '';
|
||||
}
|
||||
if (mixElement?.videoElement && rawMessage) {
|
||||
let tempData =
|
||||
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement) as OB11MessageVideo | undefined;
|
||||
url = tempData?.data.url ?? '';
|
||||
}
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
url: downloadPath,
|
||||
url: url !== '' ? url : downloadPath,
|
||||
file_size: fileSize,
|
||||
file_name: fileName,
|
||||
};
|
||||
@@ -65,7 +73,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(payload.file);
|
||||
if (contextModelIdFile) {
|
||||
const { peer, modelId } = contextModelIdFile;
|
||||
const downloadPath = await NTQQFileApi.downloadFileForModelId(peer, modelId);
|
||||
const downloadPath = await this.core.apis.FileApi.downloadFileForModelId(peer, modelId, '');
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
url: downloadPath,
|
||||
@@ -84,9 +92,9 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
}
|
||||
|
||||
//搜索名字模式
|
||||
const searchResult = (await NTQQFileApi.searchForFile([payload.file]));
|
||||
const searchResult = (await this.core.apis.FileApi.searchForFile([payload.file]));
|
||||
if (searchResult) {
|
||||
const downloadPath = await NTQQFileApi.downloadFileById(searchResult.id, parseInt(searchResult.fileSize));
|
||||
const downloadPath = await this.core.apis.FileApi.downloadFileById(searchResult.id, parseInt(searchResult.fileSize));
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
url: downloadPath,
|
||||
|
@@ -1,24 +0,0 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['string', 'number'] },
|
||||
},
|
||||
required: ['group_id'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupFileCount extends BaseAction<Payload, { count: number }> {
|
||||
actionName = ActionName.GetGroupFileCount;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]);
|
||||
return { count: ret.groupFileCounts[0] };
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['string', 'number'] },
|
||||
start_index: { type: ['string', 'number'] },
|
||||
file_count: { type: ['string', 'number'] },
|
||||
folder_id: { type: ['string', 'number'] },
|
||||
},
|
||||
required: ['group_id', 'start_index', 'file_count'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> {
|
||||
actionName = ActionName.GetGroupFileList;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
let param = {};
|
||||
if (payload.folder_id) {
|
||||
param = {
|
||||
folderId: payload.folder_id.toString(),
|
||||
};
|
||||
}
|
||||
const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), {
|
||||
sortType: 1,
|
||||
fileCount: +payload.file_count,
|
||||
startIndex: +payload.start_index,
|
||||
sortOrder: 2,
|
||||
showOnlinedocFolder: 0,
|
||||
...param
|
||||
}).catch((e) => {
|
||||
return [];
|
||||
});
|
||||
ret.forEach((e) => {
|
||||
let fileModelId = e?.fileInfo?.fileModelId;
|
||||
if (fileModelId) {
|
||||
e.fileModelId = fileModelId;
|
||||
}
|
||||
e.fileId = FileNapCatOneBotUUID.encodeModelId({ chatType: 2, peerUid: payload.group_id.toString() }, fileModelId);
|
||||
});
|
||||
return { FileList: ret };
|
||||
}
|
||||
}
|
@@ -13,12 +13,10 @@ const SchemaData = {
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class SetGroupFileFolder extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.SetGroupFileFolder;
|
||||
export class CreateGroupFileFolder extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
return (await NTQQGroupApi.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,6 +1,7 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
@@ -13,12 +14,12 @@ const SchemaData = {
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class DelGroupFile extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.DelGroupFile;
|
||||
export class DeleteGroupFile extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GOCQHTTP_DeleteGroupFile;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]);
|
||||
const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id);
|
||||
if (!data) throw new Error('Invalid file_id');
|
||||
return await this.core.apis.GroupApi.DelGroupFile(payload.group_id.toString(), [data.fileId]);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import BaseAction from '../BaseAction';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
@@ -13,12 +13,11 @@ const SchemaData = {
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class DelGroupFileFolder extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.DelGroupFileFolder;
|
||||
export class DeleteGroupFileFolder extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;
|
||||
return (await this.core.apis.GroupApi.DelGroupFileFolder(
|
||||
payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;
|
||||
}
|
||||
}
|
@@ -19,7 +19,6 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const msgId = payload.message_id || payload.id;
|
||||
if (!msgId) {
|
||||
throw Error('message_id is required');
|
||||
@@ -29,7 +28,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
|
||||
if (!rootMsg) {
|
||||
throw Error('msg not found');
|
||||
}
|
||||
const data = await NTQQMsgApi.getMultiMsg(rootMsg.Peer, rootMsg.MsgId, rootMsg.MsgId);
|
||||
const data = await this.core.apis.MsgApi.getMultiMsg(rootMsg.Peer, rootMsg.MsgId, rootMsg.MsgId);
|
||||
if (!data || data.result !== 0) {
|
||||
throw Error('找不到相关的聊天记录' + data?.errMsg);
|
||||
}
|
||||
|
@@ -27,21 +27,17 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<Response> {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const NTQQFriendApi = this.core.apis.FriendApi;
|
||||
//处理参数
|
||||
const uid = await NTQQUserApi.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;
|
||||
if (!uid) throw `记录${payload.user_id}不存在`;
|
||||
const friend = await NTQQFriendApi.isBuddy(uid);
|
||||
const friend = await this.core.apis.FriendApi.isBuddy(uid);
|
||||
const peer = { chatType: friend ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: uid };
|
||||
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 msgList = hasMessageSeq ?
|
||||
(await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await NTQQMsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||
if (msgList.length === 0) throw `消息${payload.message_seq}不存在`;
|
||||
//翻转消息
|
||||
if (isReverseOrder) msgList.reverse();
|
||||
|
35
src/onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts
Normal file
35
src/onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['string', 'number'] },
|
||||
},
|
||||
required: ['group_id'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupFileSystemInfo extends BaseAction<Payload, {
|
||||
file_count: number,
|
||||
limit_count: number, // unimplemented
|
||||
used_space: number, // todo: unimplemented, but can be implemented later
|
||||
total_space: number, // unimplemented, 10 GB by default
|
||||
}> {
|
||||
actionName = ActionName.GoCQHTTP_GetGroupFileSystemInfo;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
return {
|
||||
file_count:
|
||||
(await this.core.apis.GroupApi
|
||||
.getGroupFileCount([payload.group_id.toString()]))
|
||||
.groupFileCounts[0],
|
||||
limit_count: 10000,
|
||||
used_space: 0,
|
||||
total_space: 10 * 1024 * 1024 * 1024,
|
||||
};
|
||||
}
|
||||
}
|
37
src/onebot/action/go-cqhttp/GetGroupFilesByFolder.ts
Normal file
37
src/onebot/action/go-cqhttp/GetGroupFilesByFolder.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { OB11Entities } from '@/onebot/entities';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['string', 'number'] },
|
||||
folder_id: { type: 'string' },
|
||||
file_count: { type: ['string', 'number'] },
|
||||
},
|
||||
required: ['group_id', 'folder_id'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupFilesByFolder extends BaseAction<any, any> {
|
||||
actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder;
|
||||
payloadSchema = SchemaData;
|
||||
async _handle(payload: Payload) {
|
||||
|
||||
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
||||
sortType: 1,
|
||||
fileCount: +(payload.file_count ?? 50),
|
||||
startIndex: 0,
|
||||
sortOrder: 2,
|
||||
showOnlinedocFolder: 0,
|
||||
folderId: payload.folder_id,
|
||||
}).catch(() => []);
|
||||
return {
|
||||
files: ret.filter(item => item.fileInfo)
|
||||
.map(item => OB11Entities.file(item.peerId, item.fileInfo!)),
|
||||
folders: [] as [],
|
||||
};
|
||||
}
|
||||
}
|
@@ -22,7 +22,6 @@ export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
|
||||
if (!payload.type) {
|
||||
payload.type = WebHonorType.ALL;
|
||||
}
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
|
||||
return await this.core.apis.WebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,6 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<Response> {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
//处理参数
|
||||
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
||||
const MsgCount = +(payload.count ?? 20);
|
||||
@@ -36,7 +35,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
||||
//拉取消息
|
||||
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||
const msgList = hasMessageSeq ?
|
||||
(await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await NTQQMsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||
if (msgList.length === 0) throw `消息${payload.message_seq}不存在`;
|
||||
//翻转消息
|
||||
if (isReverseOrder) msgList.reverse();
|
||||
|
40
src/onebot/action/go-cqhttp/GetGroupRootFiles.ts
Normal file
40
src/onebot/action/go-cqhttp/GetGroupRootFiles.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
|
||||
import { OB11Entities } from '@/onebot/entities';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['string', 'number'] },
|
||||
file_count: { type: ['string', 'number'] },
|
||||
},
|
||||
required: ['group_id'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupRootFiles extends BaseAction<Payload, {
|
||||
files: OB11GroupFile[],
|
||||
folders: OB11GroupFileFolder[],
|
||||
}> {
|
||||
actionName = ActionName.GoCQHTTP_GetGroupRootFiles;
|
||||
payloadSchema = SchemaData;
|
||||
async _handle(payload: Payload) {
|
||||
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
|
||||
sortType: 1,
|
||||
fileCount: +(payload.file_count ?? 50),
|
||||
startIndex: 0,
|
||||
sortOrder: 2,
|
||||
showOnlinedocFolder: 0,
|
||||
}).catch(() => []);
|
||||
|
||||
return {
|
||||
files: ret.filter(item => item.fileInfo)
|
||||
.map(item => OB11Entities.file(item.peerId, item.fileInfo!)),
|
||||
folders: ret.filter(item => item.folderInfo)
|
||||
.map(item => OB11Entities.folder(item.peerId, item.folderInfo!)),
|
||||
};
|
||||
}
|
||||
}
|
@@ -15,8 +15,7 @@ export class GetOnlineClient extends BaseAction<void, Array<any>> {
|
||||
|
||||
async _handle(payload: void) {
|
||||
//注册监听
|
||||
const NTQQSystemApi = this.core.apis.SystemApi;
|
||||
NTQQSystemApi.getOnlineDev();
|
||||
this.core.apis.SystemApi.getOnlineDev();
|
||||
await sleep(500);
|
||||
|
||||
return [];
|
||||
|
@@ -19,10 +19,9 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
||||
actionName = ActionName.GoCQHTTP_GetStrangerInfo;
|
||||
|
||||
async _handle(payload: Payload): Promise<OB11User> {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const user_id = payload.user_id.toString();
|
||||
const extendData = await NTQQUserApi.getUserDetailInfoByUinV2(user_id);
|
||||
const uid = (await NTQQUserApi.getUidByUinV2(user_id))!;
|
||||
const extendData = await this.core.apis.UserApi.getUserDetailInfoByUinV2(user_id);
|
||||
const uid = (await this.core.apis.UserApi.getUidByUinV2(user_id))!;
|
||||
if (!uid || uid.indexOf('*') != -1) {
|
||||
return {
|
||||
...extendData.detail.simpleInfo.coreInfo,
|
||||
@@ -38,7 +37,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
||||
login_days: 0,
|
||||
};
|
||||
}
|
||||
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
|
||||
const data = { ...extendData, ...(await this.core.apis.UserApi.getUserDetailInfo(uid)) };
|
||||
return OB11Entities.stranger(data);
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,10 @@ const SchemaData = {
|
||||
content: { type: 'string' },
|
||||
image: { type: 'string' },
|
||||
pinned: { type: ['number', 'string'] },
|
||||
type: { type: ['number', 'string'] },
|
||||
confirm_required: { type: ['number', 'string'] },
|
||||
is_show_edit_card: { type: ['number', 'string'] },
|
||||
tip_window_type: { type: ['number', 'string'] },
|
||||
},
|
||||
required: ['group_id', 'content'],
|
||||
} as const satisfies JSONSchema;
|
||||
@@ -22,7 +25,7 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.GoCQHTTP_SendGroupNotice;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
|
||||
let UploadImage: { id: string, width: number, height: number } | undefined = undefined;
|
||||
if (payload.image) {
|
||||
//公告图逻辑
|
||||
@@ -38,7 +41,7 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
throw `群公告${payload.image}设置失败,获取资源失败`;
|
||||
}
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ImageUploadResult = await NTQQGroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
|
||||
const ImageUploadResult = await this.core.apis.GroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
|
||||
if (ImageUploadResult.errCode != 0) {
|
||||
throw `群公告${payload.image}设置失败,图片上传失败`;
|
||||
}
|
||||
@@ -48,12 +51,28 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
}
|
||||
UploadImage = ImageUploadResult.picInfo;
|
||||
}
|
||||
const noticePinned = +(payload.pinned ?? 0);
|
||||
const noticeConfirmRequired = +(payload.confirm_required ?? 0);
|
||||
const publishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, noticePinned, noticeConfirmRequired);
|
||||
|
||||
if (publishGroupBulletinResult.result != 0) {
|
||||
throw `设置群公告失败,错误信息:${publishGroupBulletinResult.errMsg}`;
|
||||
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.GroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, noticePinned, noticeConfirmRequired);
|
||||
const publishGroupBulletinResult = await this.core.apis.WebApi.setGroupNotice(
|
||||
payload.group_id.toString(),
|
||||
payload.content,
|
||||
noticePinned,
|
||||
noticeType,
|
||||
noticeShowEditCard,
|
||||
noticeTipWindowType,
|
||||
noticeConfirmRequired,
|
||||
UploadImage?.id,
|
||||
UploadImage?.width,
|
||||
UploadImage?.height
|
||||
);
|
||||
if (!publishGroupBulletinResult || publishGroupBulletinResult.ec != 0) {
|
||||
throw `设置群公告失败,错误信息:${publishGroupBulletinResult?.em}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -25,14 +25,13 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
|
||||
}
|
||||
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const { path, isLocal, errMsg, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
const { path, isLocal, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ret = await NTQQGroupApi.setGroupAvatar(payload.group_id.toString(), path) as any;
|
||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path) as any;
|
||||
if (!isLocal) {
|
||||
fs.unlink(path, () => {
|
||||
});
|
||||
|
@@ -19,10 +19,9 @@ export class SetQQProfile extends BaseAction<Payload, any | null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const self = this.core.selfInfo;
|
||||
const OldProfile = await NTQQUserApi.getUserDetailInfo(self.uid);
|
||||
return await NTQQUserApi.modifySelfProfile({
|
||||
const OldProfile = await this.core.apis.UserApi.getUserDetailInfo(self.uid);
|
||||
return await this.core.apis.UserApi.modifySelfProfile({
|
||||
nick: payload.nickname,
|
||||
longNick: (payload?.personal_note ?? OldProfile?.longNick) || '',
|
||||
sex: parseInt(payload?.sex ? payload?.sex.toString() : OldProfile?.sex!.toString()),
|
||||
|
@@ -22,14 +22,12 @@ export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null>
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async getPeer(payload: Payload): Promise<Peer> {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQFriendApi = this.core.apis.FriendApi;
|
||||
if (payload.user_id) {
|
||||
const peerUid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!peerUid) {
|
||||
throw `私聊${payload.user_id}不存在`;
|
||||
}
|
||||
const isBuddy = await NTQQFriendApi.isBuddy(peerUid);
|
||||
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
||||
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
||||
}
|
||||
throw new Error('缺少参数 user_id');
|
||||
|
@@ -18,16 +18,14 @@ export default class DelEssenceMsg extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
if (!msg) {
|
||||
const data = NTQQGroupApi.essenceLRU.getValue(+payload.message_id);
|
||||
const data = this.core.apis.GroupApi.essenceLRU.getValue(+payload.message_id);
|
||||
if(!data) throw new Error('消息不存在');
|
||||
const { msg_seq, msg_random, group_id } = JSON.parse(data) as { msg_seq: string, msg_random: string, group_id: string };
|
||||
return await NTQQGroupApi.removeGroupEssenceBySeq(group_id, msg_seq, msg_random);
|
||||
return await this.core.apis.GroupApi.removeGroupEssenceBySeq(group_id, msg_seq, msg_random);
|
||||
}
|
||||
return await NTQQGroupApi.removeGroupEssence(
|
||||
return await this.core.apis.GroupApi.removeGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId,
|
||||
);
|
||||
|
@@ -19,9 +19,8 @@ export class DelGroupNotice extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const group = payload.group_id.toString();
|
||||
const noticeId = payload.notice_id;
|
||||
return await NTQQGroupApi.deleteGroupBulletin(group, noticeId);
|
||||
return await this.core.apis.GroupApi.deleteGroupBulletin(group, noticeId);
|
||||
}
|
||||
}
|
||||
|
@@ -31,9 +31,7 @@ export class GetGroupEssence extends BaseAction<Payload, any> {
|
||||
}
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const msglist = (await NTQQWebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list);
|
||||
const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list);
|
||||
if (!msglist) {
|
||||
throw new Error('获取失败');
|
||||
}
|
||||
@@ -65,7 +63,7 @@ export class GetGroupEssence extends BaseAction<Payload, any> {
|
||||
//设置第一个bit为0 保证shortId为正数
|
||||
hash[0] &= 0x7f;
|
||||
const shortId = hash.readInt32BE(0);
|
||||
NTQQGroupApi.essenceLRU.set(shortId, msgTempData);
|
||||
this.core.apis.GroupApi.essenceLRU.set(shortId, msgTempData);
|
||||
return {
|
||||
msg_seq: msg.msg_seq,
|
||||
msg_random: msg.msg_random,
|
||||
|
@@ -16,21 +16,19 @@ export class GetGroupIgnoredNotifies extends BaseAction<void, any> {
|
||||
actionName = ActionName.GetGroupIgnoredNotifies;
|
||||
|
||||
async _handle(payload: void) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const ignoredNotifies = await NTQQGroupApi.getSingleScreenNotifies(true, 10);
|
||||
const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
|
||||
const retData: any = {
|
||||
join_requests: await Promise.all(
|
||||
ignoredNotifies
|
||||
.filter(notify => notify.type === 7)
|
||||
.map(async SSNotify => ({
|
||||
request_id: SSNotify.seq,
|
||||
requester_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
||||
requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
|
||||
requester_nick: SSNotify.user1?.nickName,
|
||||
group_id: SSNotify.group?.groupCode,
|
||||
group_name: SSNotify.group?.groupName,
|
||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
||||
actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
||||
}))),
|
||||
};
|
||||
|
||||
|
@@ -19,8 +19,7 @@ class GetGroupInfo extends BaseAction<Payload, OB11Group> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const group = (await NTQQGroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString());
|
||||
const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString());
|
||||
if (!group) throw `群${payload.group_id}不存在`;
|
||||
return OB11Entities.group(group);
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ import { OB11Group } from '@/onebot';
|
||||
import { OB11Entities } from '@/onebot/entities';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { Group } from '@/core/entities';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
// no_cache get时传字符串
|
||||
const SchemaData = {
|
||||
@@ -19,9 +18,9 @@ class GetGroupList extends BaseAction<Payload, OB11Group[]> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const groupList: Group[] = await NTQQGroupApi.getGroups(typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache);
|
||||
return OB11Entities.groups(groupList);
|
||||
return OB11Entities.groups(
|
||||
await this.core.apis.GroupApi.getGroups(
|
||||
typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,27 +22,25 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const isNocache = typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache;
|
||||
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error(`Uin2Uid Error ${payload.user_id}不存在`);
|
||||
const [member, info] = await Promise.allSettled([
|
||||
NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache),
|
||||
NTQQUserApi.getUserDetailInfo(uid),
|
||||
this.core.apis.GroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.UserApi.getUserDetailInfo(uid),
|
||||
]);
|
||||
if (member.status !== 'fulfilled') throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在 ${member.reason}`);
|
||||
if (member.status !== 'fulfilled') throw new Error(`群(${payload.group_id})成员${payload.user_id}获取失败 ${member.reason}`);
|
||||
if (!member.value) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
if (info.status === 'fulfilled') {
|
||||
this.core.context.logger.logDebug('群成员详细信息结果', info.value);
|
||||
Object.assign(member, info.value);
|
||||
Object.assign(member.value, info.value);
|
||||
} else {
|
||||
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息 ${info.reason}`);
|
||||
}
|
||||
const date = Math.round(Date.now() / 1000);
|
||||
const retMember = OB11Entities.groupMember(payload.group_id.toString(), member.value as GroupMember);
|
||||
const Member = await this.core.apis.GroupApi.getGroupMember(payload.group_id.toString(), retMember.user_id);
|
||||
retMember.last_sent_time = parseInt(Member?.lastSpeakTime || date.toString());
|
||||
retMember.join_time = parseInt(Member?.joinTime || date.toString());
|
||||
retMember.last_sent_time = parseInt(Member?.lastSpeakTime ?? date.toString());
|
||||
retMember.join_time = parseInt(Member?.joinTime ?? date.toString());
|
||||
return retMember;
|
||||
}
|
||||
}
|
||||
|
@@ -20,9 +20,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
const groupMembers = await NTQQGroupApi.getGroupMembersV2(payload.group_id.toString());
|
||||
const groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(payload.group_id.toString());
|
||||
const groupMembersArr = Array.from(groupMembers.values());
|
||||
|
||||
let _groupMembers = groupMembersArr.map(item => {
|
||||
@@ -48,7 +46,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
||||
});
|
||||
|
||||
if (isPrivilege) {
|
||||
const webGroupMembers = await NTQQWebApi.getGroupMembers(payload.group_id.toString());
|
||||
const webGroupMembers = await this.core.apis.WebApi.getGroupMembers(payload.group_id.toString());
|
||||
for (let i = 0, len = webGroupMembers.length; i < len; i++) {
|
||||
if (!webGroupMembers[i]?.uin) {
|
||||
continue;
|
||||
|
@@ -34,10 +34,8 @@ export class GetGroupNotice extends BaseAction<Payload, GroupNotice[]> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
|
||||
const group = payload.group_id.toString();
|
||||
const ret = await NTQQWebApi.getGroupNotice(group);
|
||||
const ret = await this.core.apis.WebApi.getGroupNotice(group);
|
||||
if (!ret) {
|
||||
throw new Error('获取公告失败');
|
||||
}
|
||||
|
@@ -18,12 +18,11 @@ export default class SetEssenceMsg extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||
if (!msg) {
|
||||
throw new Error('msg not found');
|
||||
}
|
||||
return await NTQQGroupApi.addGroupEssence(
|
||||
return await this.core.apis.GroupApi.addGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId,
|
||||
);
|
||||
|
@@ -20,10 +20,9 @@ export default class SetGroupAddRequest extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const flag = payload.flag.toString();
|
||||
const approve = payload.approve?.toString() !== 'false';
|
||||
await NTQQGroupApi.handleGroupRequest(flag,
|
||||
await this.core.apis.GroupApi.handleGroupRequest(flag,
|
||||
approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject,
|
||||
payload.reason ?? ' ',
|
||||
);
|
||||
|
@@ -21,11 +21,9 @@ export default class SetGroupAdmin extends BaseAction<Payload, null> {
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const enable = typeof payload.enable === 'string' ? payload.enable === 'true' : !!payload.enable;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('get Uid Error');
|
||||
await NTQQGroupApi.setMemberRole(payload.group_id.toString(), uid, enable ? GroupMemberRole.admin : GroupMemberRole.normal);
|
||||
await this.core.apis.GroupApi.setMemberRole(payload.group_id.toString(), uid, enable ? GroupMemberRole.admin : GroupMemberRole.normal);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -19,11 +19,9 @@ export default class SetGroupBan extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('uid error');
|
||||
await NTQQGroupApi.banMember(payload.group_id.toString(),
|
||||
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
||||
[{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]);
|
||||
return null;
|
||||
}
|
||||
|
@@ -19,9 +19,8 @@ export default class SetGroupCard extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const member = await NTQQGroupApi.getGroupMember(payload.group_id.toString(), payload.user_id.toString());
|
||||
member && await NTQQGroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || '');
|
||||
const member = await this.core.apis.GroupApi.getGroupMember(payload.group_id.toString(), payload.user_id.toString());
|
||||
if (member) await this.core.apis.GroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || '');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -20,12 +20,10 @@ export default class SetGroupKick extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const rejectReq = payload.reject_add_request?.toString() == 'true';
|
||||
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('get Uid Error');
|
||||
await NTQQGroupApi.kickMember(payload.group_id.toString(), [uid], rejectReq);
|
||||
await this.core.apis.GroupApi.kickMember(payload.group_id.toString(), [uid], rejectReq);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ export default class SetGroupLeave extends BaseAction<Payload, any> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
await NTQQGroupApi.quitGroup(payload.group_id.toString());
|
||||
await this.core.apis.GroupApi.quitGroup(payload.group_id.toString());
|
||||
}
|
||||
}
|
||||
|
@@ -17,8 +17,7 @@ export default class SetGroupName extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
await NTQQGroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
|
||||
await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -19,8 +19,7 @@ export default class SetGroupWholeBan extends BaseAction<Payload, null> {
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const enable = payload.enable?.toString() !== 'false';
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
await NTQQGroupApi.banGroup(payload.group_id.toString(), enable);
|
||||
await this.core.apis.GroupApi.banGroup(payload.group_id.toString(), enable);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -55,12 +55,7 @@ import { GoCQHTTPHandleQuickAction } from './go-cqhttp/QuickAction';
|
||||
import { GetGroupIgnoredNotifies } from './group/GetGroupIgnoredNotifies';
|
||||
import { GetOnlineClient } from './go-cqhttp/GetOnlineClient';
|
||||
import { IOCRImage, OCRImage } from './extends/OCRImage';
|
||||
import { GetGroupFileCount } from './file/GetGroupFileCount';
|
||||
import { GetGroupFileList } from './file/GetGroupFileList';
|
||||
import { TranslateEnWordToZn } from './extends/TranslateEnWordToZn';
|
||||
import { SetGroupFileFolder } from './file/SetGroupFileFolder';
|
||||
import { DelGroupFile } from './file/DelGroupFile';
|
||||
import { DelGroupFileFolder } from './file/DelGroupFileFolder';
|
||||
import { SetQQProfile } from './go-cqhttp/SetQQProfile';
|
||||
import { ShareGroupEx, SharePeer } from './extends/ShareContact';
|
||||
import { CreateCollection } from './extends/CreateCollection';
|
||||
@@ -82,10 +77,17 @@ import { SetInputStatus } from './extends/SetInputStatus';
|
||||
import { GetCSRF } from './system/GetCSRF';
|
||||
import { DelGroupNotice } from './group/DelGroupNotice';
|
||||
import { GetGroupInfoEx } from './extends/GetGroupInfoEx';
|
||||
import { DeleteGroupFile } from '@/onebot/action/go-cqhttp/DeleteGroupFile';
|
||||
import { CreateGroupFileFolder } from '@/onebot/action/go-cqhttp/CreateGroupFileFolder';
|
||||
import { DeleteGroupFileFolder } from '@/onebot/action/go-cqhttp/DeleteGroupFileFolder';
|
||||
import { GetGroupFileSystemInfo } from '@/onebot/action/go-cqhttp/GetGroupFileSystemInfo';
|
||||
import { GetGroupRootFiles } from '@/onebot/action/go-cqhttp/GetGroupRootFiles';
|
||||
import { GetGroupFilesByFolder } from '@/onebot/action/go-cqhttp/GetGroupFilesByFolder';
|
||||
|
||||
export type ActionMap = Map<string, BaseAction<any, any>>;
|
||||
|
||||
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore): ActionMap {
|
||||
|
||||
const actionHandlers = [
|
||||
new GetGroupInfoEx(obContext, core),
|
||||
new FetchEmojiLike(obContext, core),
|
||||
@@ -101,11 +103,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
||||
new MarkPrivateMsgAsRead(obContext, core),
|
||||
new SetQQAvatar(obContext, core),
|
||||
new TranslateEnWordToZn(obContext, core),
|
||||
new GetGroupFileCount(obContext, core),
|
||||
new GetGroupFileList(obContext, core),
|
||||
new SetGroupFileFolder(obContext, core),
|
||||
new DelGroupFile(obContext, core),
|
||||
new DelGroupFileFolder(obContext, core),
|
||||
new GetGroupRootFiles(obContext, core),
|
||||
// onebot11
|
||||
new SendLike(obContext, core),
|
||||
new GetMsg(obContext, core),
|
||||
@@ -173,6 +171,11 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
||||
new SetInputStatus(obContext, core),
|
||||
new GetCSRF(obContext, core),
|
||||
new DelGroupNotice(obContext, core),
|
||||
new DeleteGroupFile(obContext, core),
|
||||
new CreateGroupFileFolder(obContext, core),
|
||||
new DeleteGroupFileFolder(obContext, core),
|
||||
new GetGroupFileSystemInfo(obContext, core),
|
||||
new GetGroupFilesByFolder(obContext, core),
|
||||
];
|
||||
const actionMap = new Map();
|
||||
for (const action of actionHandlers) {
|
||||
|
@@ -23,24 +23,19 @@ class DeleteMsg extends BaseAction<Payload, void> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id));
|
||||
if (msg) {
|
||||
const ret = this.core.eventWrapper.registerListen(
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
5000,
|
||||
1000,
|
||||
(msgs) => !!msgs.find(m => m.msgId === msg.MsgId && m.recallTime !== '0'),
|
||||
).catch(() => new Promise<undefined>((resolve) => {
|
||||
resolve(undefined);
|
||||
}));
|
||||
await NTQQMsgApi.recallMsg(msg.Peer, [msg.MsgId]);
|
||||
).catch(() => undefined);
|
||||
await this.core.apis.MsgApi.recallMsg(msg.Peer, [msg.MsgId]);
|
||||
const data = await ret;
|
||||
if (!data) {
|
||||
//throw new Error('Recall failed');
|
||||
}
|
||||
//await sleep(100);
|
||||
//await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId]);
|
||||
if (!data) throw new Error('Recall failed');
|
||||
} else {
|
||||
throw new Error('Recall failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,9 +18,8 @@ type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
class ForwardSingleMsg extends BaseAction<Payload, null> {
|
||||
protected async getTargetPeer(payload: Payload): Promise<Peer> {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
if (payload.user_id) {
|
||||
const peerUid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!peerUid) {
|
||||
throw new Error(`无法找到私聊对象${payload.user_id}`);
|
||||
}
|
||||
@@ -30,13 +29,12 @@ class ForwardSingleMsg extends BaseAction<Payload, null> {
|
||||
}
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||
if (!msg) {
|
||||
throw new Error(`无法找到消息${payload.message_id}`);
|
||||
}
|
||||
const peer = await this.getTargetPeer(payload);
|
||||
const ret = await NTQQMsgApi.forwardMsg(msg.Peer,
|
||||
const ret = await this.core.apis.MsgApi.forwardMsg(msg.Peer,
|
||||
peer,
|
||||
[msg.MsgId],
|
||||
);
|
||||
|
@@ -22,7 +22,6 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
// log("history msg ids", Object.keys(msgHistory));
|
||||
if (!payload.message_id) {
|
||||
throw Error('参数message_id不能为空');
|
||||
@@ -33,7 +32,7 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
|
||||
throw new Error('消息不存在');
|
||||
}
|
||||
const peer = { guildId: '', peerUid: msgIdWithPeer?.Peer.peerUid, chatType: msgIdWithPeer.Peer.chatType };
|
||||
const msg = await NTQQMsgApi.getMsgsByMsgId(
|
||||
const msg = await this.core.apis.MsgApi.getMsgsByMsgId(
|
||||
peer,
|
||||
[msgIdWithPeer?.MsgId || payload.message_id.toString()]);
|
||||
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg.msgList[0], 'array');
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user