mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d35a19b4fd | ||
![]() |
39c4473367 | ||
![]() |
b882bc721d | ||
![]() |
405cace489 | ||
![]() |
402a7b7fc9 | ||
![]() |
8ad805e654 | ||
![]() |
b23c357f73 | ||
![]() |
f561c2b0fa | ||
![]() |
5a8eea668f | ||
![]() |
777143e502 | ||
![]() |
0d8c9a82fe | ||
![]() |
d10ab1cce3 | ||
![]() |
ec25e09d73 | ||
![]() |
cba9c78ab1 | ||
![]() |
c32db4a881 | ||
![]() |
871add3071 | ||
![]() |
e661c617a3 | ||
![]() |
d4bf721540 | ||
![]() |
d91b55faed | ||
![]() |
9687832d4d | ||
![]() |
fc3e436744 |
14
README.md
14
README.md
@@ -7,14 +7,14 @@
|
||||
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
|
||||
## 猫猫技能
|
||||
- [x] **高性能**:1K+ 群聊数目、20 线程并行发送消息毫无压力
|
||||
- [x] **多种启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **多平台支持**: 覆盖 Windows / Linux (可选 Docker) / Android Termux / MacOS
|
||||
- [x] **超高性能**:轻松数千群聊 独创消息队列
|
||||
- [x] **启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **覆盖平台**: 覆盖 Windows / Linux (可选 Docker) / Android Termux / MacOS
|
||||
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
|
||||
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **超低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
|
||||
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
|
||||
- [x] **低故障率**:快速适配最新版本,日常保证 0 Issue
|
||||
- [x] **远程管理**:自带 WebUI 支持,远程管理更加便捷
|
||||
- [x] **扩展支持**:基于 MoeHoo 的Native 可实现发包与收包
|
||||
|
||||
## 使用猫猫
|
||||
|
||||
@@ -28,7 +28,7 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
## 猫猫朋友
|
||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供部分参考
|
||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot)
|
||||
|
||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
||||
|
||||
|
@@ -33,7 +33,7 @@ if not exist "%QQpath%" (
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
|
||||
|
||||
|
@@ -2,8 +2,8 @@
|
||||
"name": "qq-chat",
|
||||
"version": "9.9.15-28418",
|
||||
"verHash": "206bfa62",
|
||||
"linuxVersion": "3.2.12-28327",
|
||||
"linuxVerHash": "f60e8252",
|
||||
"linuxVersion": "3.2.12-28418",
|
||||
"linuxVerHash": "0256c948",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"description": "QQ",
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.6.20",
|
||||
"version": "2.6.26",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
102
package.json
102
package.json
@@ -1,52 +1,52 @@
|
||||
{
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.6.20",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
"build:webui": "cd ./src/webui && vite build",
|
||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||
"depend": "cd dist && npm install --omit=dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@log4js-node/log4js-api": "^1.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/node": "^22.0.1",
|
||||
"@types/qrcode-terminal": "^0.12.2",
|
||||
"@types/ws": "^8.5.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||
"@typescript-eslint/parser": "^8.3.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.2.6",
|
||||
"vite-plugin-cp": "^4.0.8",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.13.0",
|
||||
"@protobuf-ts/plugin": "^2.9.4",
|
||||
"async-mutex": "^0.5.0",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.0.0-beta.2",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"file-type": "^19.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"image-size": "^1.1.1",
|
||||
"json-schema-to-ts": "^3.1.0",
|
||||
"log4js": "^6.9.1",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"silk-wasm": "^3.6.1",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
{
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.6.26",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
"build:webui": "cd ./src/webui && vite build",
|
||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||
"depend": "cd dist && npm install --omit=dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@log4js-node/log4js-api": "^1.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/node": "^22.0.1",
|
||||
"@types/qrcode-terminal": "^0.12.2",
|
||||
"@types/ws": "^8.5.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||
"@typescript-eslint/parser": "^8.3.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.2.6",
|
||||
"vite-plugin-cp": "^4.0.8",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"@protobuf-ts/runtime": "^2.9.4",
|
||||
"ajv": "^8.13.0",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"file-type": "^19.0.0",
|
||||
"json-schema-to-ts": "^3.1.0",
|
||||
"image-size": "^1.1.1",
|
||||
"cors": "^2.8.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"express": "^5.0.0-beta.2",
|
||||
"log4js": "^6.9.1",
|
||||
"silk-wasm": "^3.6.1",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
@@ -139,8 +139,13 @@ export class LogWrapper {
|
||||
|
||||
logMessage(msg: RawMessage, selfInfo: SelfInfo) {
|
||||
const isSelfSent = msg.senderUin === selfInfo.uin;
|
||||
this.log(`${isSelfSent ? '发送 ->' : '接收 <-'
|
||||
} ${rawMessageToText(msg)}`);
|
||||
|
||||
// Intercept grey tip
|
||||
if (msg.elements[0]?.elementType === ElementType.GreyTip) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log(`${isSelfSent ? '发送 ->' : '接收 <-' } ${rawMessageToText(msg)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +159,12 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
if (msg.chatType == ChatType.KCHATTYPEC2C) {
|
||||
tokens.push(`私聊 (${msg.peerUin})`);
|
||||
} else if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
||||
tokens.push(`群聊 (群 ${msg.peerUin} 的 ${msg.senderUin})`);
|
||||
if (recursiveLevel < 1) {
|
||||
tokens.push(`群聊 [${msg.peerName}(${msg.peerUin})]`);
|
||||
}
|
||||
if (msg.senderUin !== '0') {
|
||||
tokens.push(`[${msg.sendMemberName || msg.sendRemarkName || msg.sendNickName}(${msg.senderUin})]`);
|
||||
}
|
||||
} else if (msg.chatType == ChatType.KCHATTYPEDATALINE) {
|
||||
tokens.push('移动设备');
|
||||
} else /* temp */ {
|
||||
|
@@ -53,26 +53,22 @@ export class QQBasicInfoWrapper {
|
||||
}
|
||||
|
||||
//此方法不要直接使用
|
||||
getQUAInternal() {
|
||||
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`;
|
||||
}
|
||||
getQUAFallback() {
|
||||
const platformMapping: Partial<Record<NodeJS.Platform, string>> = {
|
||||
win32: `V1_WIN_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`,
|
||||
darwin: `V1_MAC_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`,
|
||||
linux: `V1_LNX_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`,
|
||||
};
|
||||
return platformMapping[systemPlatform] ?? (platformMapping.win32)!;
|
||||
}
|
||||
|
||||
getAppidInternal() {
|
||||
switch (systemPlatform) {
|
||||
case 'linux':
|
||||
return '537246140';
|
||||
case 'darwin':
|
||||
return '537246140';
|
||||
default:
|
||||
return '537246092';
|
||||
}
|
||||
getAppIdFallback() {
|
||||
const platformMapping: Partial<Record<NodeJS.Platform, string>> = {
|
||||
win32: '537246092',
|
||||
darwin: '537246140',
|
||||
linux: '537246140',
|
||||
};
|
||||
return platformMapping[systemPlatform] ?? '537246092';
|
||||
}
|
||||
|
||||
getAppidV2(): { appid: string; qua: string } {
|
||||
@@ -88,6 +84,6 @@ export class QQBasicInfoWrapper {
|
||||
// else
|
||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
|
||||
return { appid: this.getAppidInternal(), qua: this.getQUAInternal() };
|
||||
return { appid: this.getAppIdFallback(), qua: this.getQUAFallback() };
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.6.20';
|
||||
export const napCatVersion = '2.6.26';
|
||||
|
@@ -365,22 +365,43 @@ export class NTQQFileApi {
|
||||
|
||||
if (url) {
|
||||
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
||||
const urlRkey = parsedUrl.searchParams.get('rkey');
|
||||
const imageAppid = parsedUrl.searchParams.get('appid');
|
||||
const isNTV2 = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||
if (isNTV2) {
|
||||
let rkey = parsedUrl.searchParams.get('rkey');
|
||||
if (rkey) {
|
||||
return IMAGE_HTTP_HOST_NT + url;
|
||||
}
|
||||
const rkeyData = await this.rkeyManager.getRkey();
|
||||
rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST_NT + url + `${rkey}`;
|
||||
} else {
|
||||
return IMAGE_HTTP_HOST + url;
|
||||
const imageFileId = parsedUrl.searchParams.get('fileid');
|
||||
|
||||
let rkeyData = {
|
||||
private_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qEc3Rbib9LP4',
|
||||
group_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qffcqm614gds',
|
||||
online_rkey: false
|
||||
};
|
||||
|
||||
try {
|
||||
let tempRkeyData = await this.rkeyManager.getRkey();
|
||||
rkeyData.group_rkey = tempRkeyData.group_rkey;
|
||||
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
||||
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
||||
} catch (e) {
|
||||
this.context.logger.logError.bind(this.context.logger)('获取rkey失败 Fallback Old Mode', e);
|
||||
}
|
||||
} else if (fileMd5 || md5HexStr) {
|
||||
|
||||
|
||||
if (isNTV2 && urlRkey) {
|
||||
return IMAGE_HTTP_HOST_NT + urlRkey;
|
||||
} else if (isNTV2 && rkeyData.online_rkey) {
|
||||
let rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST_NT + url + `&rkey=${rkey}`;
|
||||
} else if (isNTV2 && imageFileId) {
|
||||
let rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||
return IMAGE_HTTP_HOST + `/download?appid=${imageAppid}&fileid=${imageFileId}&rkey=${rkey}`;
|
||||
}
|
||||
|
||||
}
|
||||
//到这里说明可能是旧客户端
|
||||
if (fileMd5 || md5HexStr) {
|
||||
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
|
||||
}
|
||||
|
||||
this.context.logger.logDebug('图片url获取失败', element);
|
||||
return '';
|
||||
}
|
||||
|
@@ -909,11 +909,26 @@ export interface RawMessage {
|
||||
*/
|
||||
peerUin: string;
|
||||
|
||||
/**
|
||||
* 好友备注(如果是好友消息)
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
/**
|
||||
* 群名(如果是群消息)
|
||||
*/
|
||||
peerName: string;
|
||||
|
||||
/**
|
||||
* 发送者昵称(如果是好友消息)
|
||||
*/
|
||||
sendNickName: string;
|
||||
|
||||
/**
|
||||
* 发送者好友备注(如果是群消息并且有发送者好友)
|
||||
*/
|
||||
sendRemarkName: string;
|
||||
|
||||
/**
|
||||
* 发送者群名片(如果是群消息)
|
||||
*/
|
||||
@@ -974,4 +989,4 @@ export interface MsgReqType {
|
||||
extraCnt: number
|
||||
}
|
||||
//getMsgsIncludeSelf Peer必须 byType 1
|
||||
//getMsgsWithMsgTimeAndClientSeqForC2C Peer必须 byType 3
|
||||
//getMsgsWithMsgTimeAndClientSeqForC2C Peer必须 byType 3
|
||||
|
14
src/core/external/appid.json
vendored
14
src/core/external/appid.json
vendored
@@ -15,6 +15,10 @@
|
||||
"appid": 537246140,
|
||||
"qua": "V1_LNX_NQ_3.2.12_28131_GW_B"
|
||||
},
|
||||
"6.9.55-28131": {
|
||||
"appid": 537246115,
|
||||
"qua": "V1_MAC_NQ_6.9.55_28131_GW_B"
|
||||
},
|
||||
"9.9.15-28327":{
|
||||
"appid": 537249321,
|
||||
"qua": "V1_WIN_NQ_9.9.15_28327_GW_B"
|
||||
@@ -30,5 +34,13 @@
|
||||
"3.2.12-28418":{
|
||||
"appid": 537249393,
|
||||
"qua": "V1_LNX_NQ_3.2.12_28418_GW_B"
|
||||
},
|
||||
"6.9.56-28418": {
|
||||
"appid": 537249367,
|
||||
"qua": "V1_MAC_NQ_6.9.56_28418_GW_B"
|
||||
},
|
||||
"9.9.15-28498":{
|
||||
"appid": 537249321,
|
||||
"qua": "V1_WIN_NQ_9.9.15_28498_GW_B"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,8 @@ export class RkeyManager {
|
||||
try {
|
||||
await this.refreshRkey();
|
||||
} catch (e) {
|
||||
this.logger.logError.bind(this.logger)('获取rkey失败', e);
|
||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||
//this.logger.logError.bind(this.logger)('获取rkey失败', e);
|
||||
}
|
||||
}
|
||||
return this.rkeyData;
|
||||
@@ -42,9 +43,18 @@ export class RkeyManager {
|
||||
//刷新rkey
|
||||
for (const url of this.serverUrl) {
|
||||
try {
|
||||
this.rkeyData = await RequestUtil.HttpGetJson<ServerRkeyData>(url, 'GET');
|
||||
let temp = await RequestUtil.HttpGetJson<ServerRkeyData>(url, 'GET');
|
||||
this.rkeyData = {
|
||||
group_rkey: temp.group_rkey.slice(6),
|
||||
private_rkey: temp.private_rkey.slice(6),
|
||||
expired_time: temp.expired_time
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.logError.bind(this.logger)(`[Rkey] Get Rkey ${url} Error `, e);
|
||||
//是否为最后一个url
|
||||
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
||||
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,11 +20,11 @@ import { LogLevel, LogWrapper } from '@/common/log';
|
||||
import { NodeIKernelLoginService } from '@/core/services';
|
||||
import { QQBasicInfoWrapper } from '@/common/qq-basic-info';
|
||||
import { NapCatPathWrapper } from '@/common/path';
|
||||
import path, { resolve } from 'node:path';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { hostname, systemName, systemVersion } from '@/common/system';
|
||||
import { NTEventWrapper } from '@/common/event';
|
||||
import { ChatType, DataSource, GroupMember, KickedOffLineInfo, Peer, SelfInfo, SelfStatusInfo } 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';
|
||||
@@ -257,19 +257,12 @@ export async function genSessionConfig(
|
||||
): Promise<WrapperSessionInitConfig> {
|
||||
const downloadPath = path.join(account_path, 'NapCat', 'temp');
|
||||
fs.mkdirSync(downloadPath, { recursive: true });
|
||||
//os.platform()
|
||||
let systemPlatform = PlatformType.KWINDOWS;
|
||||
switch (os.platform()) {
|
||||
case 'win32':
|
||||
systemPlatform = PlatformType.KWINDOWS;
|
||||
break;
|
||||
case 'darwin':
|
||||
systemPlatform = PlatformType.KMAC;
|
||||
break;
|
||||
case 'linux':
|
||||
systemPlatform = PlatformType.KLINUX;
|
||||
break;
|
||||
}
|
||||
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
||||
win32: PlatformType.KWINDOWS,
|
||||
darwin: PlatformType.KMAC,
|
||||
linux: PlatformType.KLINUX,
|
||||
};
|
||||
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||
return {
|
||||
selfUin,
|
||||
selfUid,
|
||||
|
21
src/core/proto/ImageFileId.ts
Normal file
21
src/core/proto/ImageFileId.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { MessageType, BinaryReader, ScalarType, BinaryWriter } from '@protobuf-ts/runtime';
|
||||
|
||||
export const FileId = new MessageType("FileId", [
|
||||
{ no: 2, name: "sha1", kind: "scalar", T: ScalarType.BYTES },
|
||||
{ no: 4, name: "appid", kind: "scalar", T: ScalarType.UINT32 },
|
||||
]);
|
||||
|
||||
export function encodePBFileId(message: any) {
|
||||
return FileId.internalBinaryWrite(message, new BinaryWriter(), {
|
||||
writerFactory: () => new BinaryWriter(),
|
||||
writeUnknownFields: false
|
||||
}).finish();
|
||||
}
|
||||
|
||||
export function decodePBFileId(buffer: Uint8Array): any {
|
||||
const reader = new BinaryReader(buffer);
|
||||
return FileId.internalBinaryRead(reader, reader.len, {
|
||||
readUnknownField: true,
|
||||
readerFactory: () => new BinaryReader(buffer)
|
||||
});
|
||||
}
|
30
src/core/proto/Poke.ts
Normal file
30
src/core/proto/Poke.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { MessageType, ScalarType, BinaryWriter } from '@protobuf-ts/runtime';
|
||||
|
||||
export const OidbSvcTrpcTcpBase = new MessageType("oidb_svc_trpctcp_base", [
|
||||
{ no: 1, name: "command", kind: "scalar", T: ScalarType.UINT32 },
|
||||
{ no: 2, name: "subcommand", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||
{ no: 4, name: "body", kind: "scalar", T: ScalarType.BYTES, opt: true }
|
||||
]);
|
||||
|
||||
export const OidbSvcTrpcTcp0XED3_1 = new MessageType("oidb_svc_trpctcp_0xed3_1", [
|
||||
{ no: 1, name: "uin", kind: "scalar", T: ScalarType.UINT32 },
|
||||
{ no: 2, name: "groupuin", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||
{ no: 5, name: "frienduin", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||
{ no: 6, name: "ext", kind: "scalar", T: ScalarType.UINT32 }
|
||||
]);
|
||||
|
||||
export function encodeGroupPoke(groupUin: string, PeerUin: string) {
|
||||
let Body = OidbSvcTrpcTcp0XED3_1.toBinary
|
||||
({
|
||||
uin: parseInt(PeerUin),
|
||||
groupuin: parseInt(groupUin),
|
||||
ext: 0
|
||||
});
|
||||
//console.log(Body)
|
||||
return OidbSvcTrpcTcpBase.toBinary
|
||||
({
|
||||
command: 0xed3,
|
||||
subcommand: 1,
|
||||
body: Body
|
||||
});
|
||||
}
|
@@ -4,7 +4,7 @@ import { dlopen } from "process";
|
||||
import fs from "fs";
|
||||
export class Native {
|
||||
platform: string;
|
||||
supportedPlatforms = ['win32'];
|
||||
supportedPlatforms = [];
|
||||
MoeHooExport: any = { exports: {} };
|
||||
recallHookEnabled: boolean = false;
|
||||
inited = true;
|
||||
|
@@ -139,8 +139,7 @@ export class OneBotGroupApi {
|
||||
}
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
||||
const type = json.items[json.items.length - 1]?.txt;
|
||||
switch (type) {
|
||||
case "头衔": {
|
||||
if (type === "头衔") {
|
||||
const memberUin = json.items[1].param[0];
|
||||
const title = json.items[3].txt;
|
||||
logger.logDebug('收到群成员新头衔消息', json);
|
||||
@@ -150,11 +149,10 @@ export class OneBotGroupApi {
|
||||
parseInt(memberUin),
|
||||
title,
|
||||
);
|
||||
}
|
||||
case "移出":
|
||||
} else if (type === "移出") {
|
||||
logger.logDebug('收到机器人被踢消息', json);
|
||||
return;
|
||||
default:
|
||||
} else {
|
||||
logger.logWarn('收到未知的灰条消息', json);
|
||||
}
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ export class NapCatOneBot11Adapter {
|
||||
};
|
||||
this.actions = createActionMap(this, core);
|
||||
this.networkManager = new OB11NetworkManager();
|
||||
this.registerNative(core, context).then().catch();
|
||||
this.registerNative(core, context).catch(e => this.context.logger.logWarn.bind(this.context.logger)('初始化Native失败', e)).then();
|
||||
this.InitOneBot()
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
|
||||
|
||||
@@ -275,7 +275,7 @@ export class NapCatOneBot11Adapter {
|
||||
msgListener.onRecvSysMsg = (msg) => {
|
||||
this.apis.MsgApi.parseSysMessage(msg).then((event) => {
|
||||
if (event) this.networkManager.emitEvent(event);
|
||||
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructSysMessage error: ', e));
|
||||
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructSysMessage error: ', e, '\n Parse Hex:', Buffer.from(msg).toString('hex')));
|
||||
};
|
||||
|
||||
msgListener.onInputStatusPush = async data => {
|
||||
|
@@ -69,18 +69,12 @@ export async function NCoreInitShell() {
|
||||
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
|
||||
return [dataPath, dataPathGlobal];
|
||||
})();
|
||||
let systemPlatform = PlatformType.KWINDOWS;
|
||||
switch (os.platform()) {
|
||||
case 'win32':
|
||||
systemPlatform = PlatformType.KWINDOWS;
|
||||
break;
|
||||
case 'darwin':
|
||||
systemPlatform = PlatformType.KMAC;
|
||||
break;
|
||||
case 'linux':
|
||||
systemPlatform = PlatformType.KLINUX;
|
||||
break;
|
||||
}
|
||||
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
||||
win32: PlatformType.KWINDOWS,
|
||||
darwin: PlatformType.KMAC,
|
||||
linux: PlatformType.KLINUX,
|
||||
};
|
||||
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
||||
// from initConfig
|
||||
engine.initWithDeskTopConfig(
|
||||
|
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V2.6.20', 'napcat-update-button', 'secondary'),
|
||||
SettingButton('V2.6.26', 'napcat-update-button', 'secondary'),
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V2.6.20", "napcat-update-button", "secondary")
|
||||
SettingButton("V2.6.26", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
Reference in New Issue
Block a user