mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
42ee83c54f | ||
![]() |
e631f69621 | ||
![]() |
ce8760a39a | ||
![]() |
ff952956de | ||
![]() |
28f3ff4971 | ||
![]() |
19e728c3cb | ||
![]() |
269773ed6b | ||
![]() |
e0d32417e1 | ||
![]() |
9fa6083bed | ||
![]() |
4d2fccdfb4 | ||
![]() |
c1c4bdfe94 |
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "3.3.22",
|
"version": "3.4.0",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "3.3.22",
|
"version": "3.4.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:framework": "vite build --mode framework",
|
"build:framework": "vite build --mode framework",
|
||||||
"build:shell": "vite build --mode shell",
|
"build:shell": "vite build --mode shell",
|
||||||
|
@@ -9,6 +9,15 @@ interface InternalMapKey {
|
|||||||
checker: ((...args: any[]) => boolean) | undefined;
|
checker: ((...args: any[]) => boolean) | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnsureFunc<T> = T extends (...args: any) => any ? T : never;
|
||||||
|
|
||||||
|
type FuncKeys<T> = Extract<
|
||||||
|
{
|
||||||
|
[K in keyof T]: EnsureFunc<T[K]> extends never ? never : K;
|
||||||
|
}[keyof T],
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
export type ListenerClassBase = Record<string, string>;
|
export type ListenerClassBase = Record<string, string>;
|
||||||
|
|
||||||
export class NTEventWrapper {
|
export class NTEventWrapper {
|
||||||
@@ -43,10 +52,8 @@ export class NTEventWrapper {
|
|||||||
|
|
||||||
createEventFunction<
|
createEventFunction<
|
||||||
Service extends keyof ServiceNamingMapping,
|
Service extends keyof ServiceNamingMapping,
|
||||||
ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
|
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||||
// eslint-disable-next-line
|
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
||||||
// @ts-ignore
|
|
||||||
T extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
|
|
||||||
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
||||||
const eventNameArr = eventName.split('/');
|
const eventNameArr = eventName.split('/');
|
||||||
type eventType = {
|
type eventType = {
|
||||||
@@ -98,10 +105,8 @@ export class NTEventWrapper {
|
|||||||
|
|
||||||
async callNoListenerEvent<
|
async callNoListenerEvent<
|
||||||
Service extends keyof ServiceNamingMapping,
|
Service extends keyof ServiceNamingMapping,
|
||||||
ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
|
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||||
// eslint-disable-next-line
|
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
||||||
// @ts-ignore
|
|
||||||
EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
|
|
||||||
>(
|
>(
|
||||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||||
...args: Parameters<EventType>
|
...args: Parameters<EventType>
|
||||||
@@ -111,10 +116,8 @@ export class NTEventWrapper {
|
|||||||
|
|
||||||
async registerListen<
|
async registerListen<
|
||||||
Listener extends keyof ListenerNamingMapping,
|
Listener extends keyof ListenerNamingMapping,
|
||||||
ListenerMethod extends Exclude<keyof ListenerNamingMapping[Listener], symbol>,
|
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||||
// eslint-disable-next-line
|
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>,
|
||||||
// @ts-ignore
|
|
||||||
ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod],
|
|
||||||
>(
|
>(
|
||||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||||
waitTimes = 1,
|
waitTimes = 1,
|
||||||
@@ -164,15 +167,11 @@ export class NTEventWrapper {
|
|||||||
|
|
||||||
async callNormalEventV2<
|
async callNormalEventV2<
|
||||||
Service extends keyof ServiceNamingMapping,
|
Service extends keyof ServiceNamingMapping,
|
||||||
ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
|
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||||
Listener extends keyof ListenerNamingMapping,
|
Listener extends keyof ListenerNamingMapping,
|
||||||
ListenerMethod extends Exclude<keyof ListenerNamingMapping[Listener], symbol>,
|
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||||
// eslint-disable-next-line
|
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
||||||
// @ts-ignore
|
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
||||||
EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
|
|
||||||
// eslint-disable-next-line
|
|
||||||
// @ts-ignore
|
|
||||||
ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod]
|
|
||||||
>(
|
>(
|
||||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||||
|
@@ -52,7 +52,7 @@ export class FileNapCatOneBotUUID {
|
|||||||
const [, , chatType, peerUid, modelId, fileId, fileUUID = undefined] = data;
|
const [, , chatType, peerUid, modelId, fileId, fileUUID = undefined] = data;
|
||||||
return {
|
return {
|
||||||
peer: {
|
peer: {
|
||||||
chatType: chatType as any,
|
chatType: +chatType,
|
||||||
peerUid: peerUid,
|
peerUid: peerUid,
|
||||||
},
|
},
|
||||||
modelId,
|
modelId,
|
||||||
@@ -89,7 +89,7 @@ export class FileNapCatOneBotUUID {
|
|||||||
const [, , chatType, peerUid, msgId, elementId, fileUUID = undefined] = data;
|
const [, , chatType, peerUid, msgId, elementId, fileUUID = undefined] = data;
|
||||||
return {
|
return {
|
||||||
peer: {
|
peer: {
|
||||||
chatType: chatType as any,
|
chatType: +chatType,
|
||||||
peerUid: peerUid,
|
peerUid: peerUid,
|
||||||
},
|
},
|
||||||
msgId,
|
msgId,
|
||||||
@@ -245,3 +245,36 @@ export function stringifyWithBigInt(obj: any) {
|
|||||||
typeof value === 'bigint' ? value.toString() : value
|
typeof value === 'bigint' ? value.toString() : value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseAppidFromMajor(nodeMajor: string): string | undefined {
|
||||||
|
const hexSequence = "A4 09 00 00 00 35";
|
||||||
|
const sequenceBytes = Buffer.from(hexSequence.replace(/ /g, ""), "hex");
|
||||||
|
const filePath = path.resolve(nodeMajor);
|
||||||
|
const fileContent = fs.readFileSync(filePath);
|
||||||
|
|
||||||
|
let searchPosition = 0;
|
||||||
|
while (true) {
|
||||||
|
const index = fileContent.indexOf(sequenceBytes, searchPosition);
|
||||||
|
if (index === -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = index + sequenceBytes.length - 1;
|
||||||
|
const end = fileContent.indexOf(0x00, start);
|
||||||
|
if (end === -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const content = fileContent.subarray(start, end);
|
||||||
|
if (!content.every(byte => byte === 0x00)) {
|
||||||
|
try {
|
||||||
|
return content.toString("utf-8");
|
||||||
|
} catch (error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPosition = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
@@ -23,10 +23,10 @@ export class LimitedHashTable<K, V> {
|
|||||||
}
|
}
|
||||||
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
||||||
const oldestKey = this.keyToValue.keys().next().value;
|
const oldestKey = this.keyToValue.keys().next().value;
|
||||||
// @ts-ignore
|
if (oldestKey !== undefined) {
|
||||||
this.valueToKey.delete(this.keyToValue.get(oldestKey)!);
|
this.valueToKey.delete(this.keyToValue.get(oldestKey) as V);
|
||||||
// @ts-ignore
|
this.keyToValue.delete(oldestKey);
|
||||||
this.keyToValue.delete(oldestKey);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { systemPlatform } from '@/common/system';
|
import { systemPlatform } from '@/common/system';
|
||||||
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath } from './helper';
|
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath, parseAppidFromMajor } from './helper';
|
||||||
import AppidTable from '@/core/external/appid.json';
|
import AppidTable from '@/core/external/appid.json';
|
||||||
import { LogWrapper } from './log';
|
import { LogWrapper } from './log';
|
||||||
|
import { getMajorPath } from '@/core';
|
||||||
|
|
||||||
export class QQBasicInfoWrapper {
|
export class QQBasicInfoWrapper {
|
||||||
QQMainPath: string | undefined;
|
QQMainPath: string | undefined;
|
||||||
@@ -72,6 +73,7 @@ export class QQBasicInfoWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAppidV2(): { appid: string; qua: string } {
|
getAppidV2(): { appid: string; qua: string } {
|
||||||
|
// 通过已有表 性能好
|
||||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||||
const fullVersion = this.getFullQQVesion();
|
const fullVersion = this.getFullQQVesion();
|
||||||
if (fullVersion) {
|
if (fullVersion) {
|
||||||
@@ -80,10 +82,22 @@ export class QQBasicInfoWrapper {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 通过Major拉取 性能差
|
||||||
// else
|
try {
|
||||||
|
let majorAppid = this.getAppidV2ByMajor(fullVersion);
|
||||||
|
if (majorAppid) { return { appid: majorAppid, qua: this.getQUAFallback() }; }
|
||||||
|
} catch (error) {
|
||||||
|
this.context.logger.log(`[QQ版本兼容性检测] 通过Major 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||||
|
}
|
||||||
|
// 最终兜底为老版本
|
||||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||||
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
|
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
|
||||||
return { appid: this.getAppIdFallback(), qua: this.getQUAFallback() };
|
return { appid: this.getAppIdFallback(), qua: this.getQUAFallback() };
|
||||||
}
|
}
|
||||||
|
getAppidV2ByMajor(QQVersion: string) {
|
||||||
|
let majorPath = getMajorPath(QQVersion);
|
||||||
|
let appid = parseAppidFromMajor(majorPath);
|
||||||
|
return appid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '3.3.22';
|
export const napCatVersion = '3.4.0';
|
||||||
|
@@ -12,7 +12,6 @@ import {
|
|||||||
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
||||||
import { LimitedHashTable } from '@/common/message-unique';
|
import { LimitedHashTable } from '@/common/message-unique';
|
||||||
import { NTEventWrapper } from '@/common/event';
|
import { NTEventWrapper } from '@/common/event';
|
||||||
import { b, c } from 'vite/dist/node/types.d-aGj9QkWt';
|
|
||||||
|
|
||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
|
@@ -3,6 +3,9 @@ import { InstanceContext, NapCatCore } from '@/core';
|
|||||||
import { GeneralCallResult } from '@/core/services/common';
|
import { GeneralCallResult } from '@/core/services/common';
|
||||||
|
|
||||||
export class NTQQMsgApi {
|
export class NTQQMsgApi {
|
||||||
|
getMsgByClientSeqAndTime(peer: Peer, replyMsgClientSeq: string, replyMsgTime: string) {
|
||||||
|
return this.context.session.getMsgService().getMsgByClientSeqAndTime(peer, replyMsgClientSeq, replyMsgTime);
|
||||||
|
}
|
||||||
// nt_qq//global//nt_data//Emoji//emoji-resource//sysface_res/apng/ 下可以看到所有QQ表情预览
|
// 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
|
// nt_qq\global\nt_data\Emoji\emoji-resource\face_config.json 里面有所有表情的id, 自带表情id是QSid, 标准emoji表情id是QCid
|
||||||
// 其实以官方文档为准是最好的,https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType
|
// 其实以官方文档为准是最好的,https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType
|
||||||
@@ -22,7 +25,9 @@ export class NTQQMsgApi {
|
|||||||
async sendShowInputStatusReq(peer: Peer, eventType: number) {
|
async sendShowInputStatusReq(peer: Peer, eventType: number) {
|
||||||
return this.context.session.getMsgService().sendShowInputStatusReq(peer.chatType, eventType, peer.peerUid);
|
return this.context.session.getMsgService().sendShowInputStatusReq(peer.chatType, eventType, peer.peerUid);
|
||||||
}
|
}
|
||||||
|
async getSourceOfReplyMsgV2(peer: Peer, clientSeq: string, time: string) {
|
||||||
|
return this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, clientSeq, time);
|
||||||
|
}
|
||||||
async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
||||||
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged Mlikiowa
|
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged Mlikiowa
|
||||||
return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, count);
|
return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, count);
|
||||||
@@ -106,9 +111,9 @@ export class NTQQMsgApi {
|
|||||||
pageLimit: 1,
|
pageLimit: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//@deprecated
|
// 客户端还在用别慌
|
||||||
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, isReverseOrder: boolean) {
|
||||||
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, isReverseOrder);
|
||||||
}
|
}
|
||||||
async getMsgExBySeq(peer: Peer, msgSeq: string) {
|
async getMsgExBySeq(peer: Peer, msgSeq: string) {
|
||||||
const DateNow = Math.floor(Date.now() / 1000);
|
const DateNow = Math.floor(Date.now() / 1000);
|
||||||
|
@@ -191,7 +191,7 @@ export class NTQQPacketApi {
|
|||||||
async sendMiniAppShareInfoReq(param: MiniAppReqParams) {
|
async sendMiniAppShareInfoReq(param: MiniAppReqParams) {
|
||||||
const data = this.packetSession?.packer.packMiniAppAdaptShareInfo(param);
|
const data = this.packetSession?.packer.packMiniAppAdaptShareInfo(param);
|
||||||
const ret = await this.sendPacket("LightAppSvc.mini_app_share.AdaptShareInfo", data!, true);
|
const ret = await this.sendPacket("LightAppSvc.mini_app_share.AdaptShareInfo", data!, true);
|
||||||
const body = new NapProtoMsg(MiniAppAdaptShareInfoResp).decode(Buffer.from(ret.hex_data, 'hex'))
|
const body = new NapProtoMsg(MiniAppAdaptShareInfoResp).decode(Buffer.from(ret.hex_data, 'hex'));
|
||||||
return JSON.parse(body.content.jsonContent) as MiniAppRawData;
|
return JSON.parse(body.content.jsonContent) as MiniAppRawData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,7 @@ type ElementFullBase = Omit<MessageElement, 'elementType' | 'elementId' | 'extBu
|
|||||||
|
|
||||||
type ElementBase<
|
type ElementBase<
|
||||||
K extends keyof ElementFullBase,
|
K extends keyof ElementFullBase,
|
||||||
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = {}
|
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = object
|
||||||
> = {
|
> = {
|
||||||
[P in K]:
|
[P in K]:
|
||||||
S[P] extends Array<infer U>
|
S[P] extends Array<infer U>
|
||||||
|
4
src/core/external/appid.json
vendored
4
src/core/external/appid.json
vendored
@@ -58,5 +58,9 @@
|
|||||||
"3.2.13-28971": {
|
"3.2.13-28971": {
|
||||||
"appid": 537249848,
|
"appid": 537249848,
|
||||||
"qua": "V1_LNX_NQ_3.2.13_28971_GW_B"
|
"qua": "V1_LNX_NQ_3.2.13_28971_GW_B"
|
||||||
|
},
|
||||||
|
"6.9.58-28971": {
|
||||||
|
"appid": 537249826,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.58_28971_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -62,7 +62,26 @@ export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
|
|||||||
process.dlopen(nativemodule, wrapperNodePath);
|
process.dlopen(nativemodule, wrapperNodePath);
|
||||||
return nativemodule.exports;
|
return nativemodule.exports;
|
||||||
}
|
}
|
||||||
|
export function getMajorPath(QQVersion: string): string {
|
||||||
|
// major.node
|
||||||
|
let appPath;
|
||||||
|
if (os.platform() === 'darwin') {
|
||||||
|
appPath = path.resolve(path.dirname(process.execPath), '../Resources/app');
|
||||||
|
} else if (os.platform() === 'linux') {
|
||||||
|
appPath = path.resolve(path.dirname(process.execPath), './resources/app');
|
||||||
|
} else {
|
||||||
|
appPath = path.resolve(path.dirname(process.execPath), `./versions/${QQVersion}/`);
|
||||||
|
}
|
||||||
|
let majorPath = path.resolve(appPath, 'major.node');
|
||||||
|
if (!fs.existsSync(majorPath)) {
|
||||||
|
majorPath = path.join(appPath, `./resources/app/major.node`);
|
||||||
|
}
|
||||||
|
//老版本兼容 未来去掉
|
||||||
|
if (!fs.existsSync(majorPath)) {
|
||||||
|
majorPath = path.join(path.dirname(process.execPath), `./resources/app/versions/${QQVersion}/major.node`);
|
||||||
|
}
|
||||||
|
return majorPath;
|
||||||
|
}
|
||||||
export class NapCatCore {
|
export class NapCatCore {
|
||||||
readonly context: InstanceContext;
|
readonly context: InstanceContext;
|
||||||
readonly apis: StableNTApiWrapper;
|
readonly apis: StableNTApiWrapper;
|
||||||
@@ -100,7 +119,7 @@ export class NapCatCore {
|
|||||||
if (!fs.existsSync(this.NapCatTempPath)) {
|
if (!fs.existsSync(this.NapCatTempPath)) {
|
||||||
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
|
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
|
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
|
||||||
|
|
||||||
this.context.logger.setFileLogEnabled(
|
this.context.logger.setFileLogEnabled(
|
||||||
@@ -140,7 +159,7 @@ export class NapCatCore {
|
|||||||
};
|
};
|
||||||
//await sleep(2500);
|
//await sleep(2500);
|
||||||
this.context.session.getMsgService().addKernelMsgListener(
|
this.context.session.getMsgService().addKernelMsgListener(
|
||||||
proxiedListenerOf(msgListener, this.context.logger) as any,
|
proxiedListenerOf(msgListener, this.context.logger),
|
||||||
);
|
);
|
||||||
|
|
||||||
const profileListener = new NodeIKernelProfileListener();
|
const profileListener = new NodeIKernelProfileListener();
|
||||||
@@ -236,7 +255,7 @@ export class NapCatCore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.context.session.getGroupService().addKernelGroupListener(
|
this.context.session.getGroupService().addKernelGroupListener(
|
||||||
proxiedListenerOf(groupListener, this.context.logger) as any,
|
proxiedListenerOf(groupListener, this.context.logger),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +295,7 @@ export async function genSessionConfig(
|
|||||||
d2: '',
|
d2: '',
|
||||||
d2Key: '',
|
d2Key: '',
|
||||||
machineId: '',
|
machineId: '',
|
||||||
platform: systemPlatform, // 3是Windows?
|
platform: systemPlatform, // 3是Windows?
|
||||||
platVer: systemVersion, // 系统版本号, 应该可以固定
|
platVer: systemVersion, // 系统版本号, 应该可以固定
|
||||||
appid: QQVersionAppid,
|
appid: QQVersionAppid,
|
||||||
rdeliveryConfig: {
|
rdeliveryConfig: {
|
||||||
|
@@ -38,7 +38,7 @@ export abstract class MiniAppInfo {
|
|||||||
});
|
});
|
||||||
MiniAppInfo.appMap.set("bili", this);
|
MiniAppInfo.appMap.set("bili", this);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
static WeiBo = new class extends MiniAppInfo {
|
static WeiBo = new class extends MiniAppInfo {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -56,7 +56,7 @@ export abstract class MiniAppInfo {
|
|||||||
});
|
});
|
||||||
MiniAppInfo.appMap.set("weibo", this);
|
MiniAppInfo.appMap.set("weibo", this);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MiniAppInfoHelper {
|
export class MiniAppInfoHelper {
|
||||||
|
@@ -742,6 +742,6 @@ export class PacketPacker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -61,35 +61,35 @@ export function ProtoField(no: number, type: ScalarType | (() => ProtoMessageTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoFieldReturnType<T extends unknown, E extends boolean> = NonNullable<T> extends ScalarProtoFieldType<infer S, infer O, infer R>
|
type ProtoFieldReturnType<T, E extends boolean> = NonNullable<T> extends ScalarProtoFieldType<infer S, infer O, infer R>
|
||||||
? ScalarTypeToTsType<S>
|
? ScalarTypeToTsType<S>
|
||||||
: T extends NonNullable<MessageProtoFieldType<infer S, infer O, infer R>>
|
: T extends NonNullable<MessageProtoFieldType<infer S, infer O, infer R>>
|
||||||
? NonNullable<NapProtoStructType<ReturnType<S>, E>>
|
? NonNullable<NapProtoStructType<ReturnType<S>, E>>
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
type RequiredFieldsBaseType<T extends unknown, E extends boolean> = {
|
type RequiredFieldsBaseType<T, E extends boolean> = {
|
||||||
[K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase<K & string>]:
|
[K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase<K & string>]:
|
||||||
T[K] extends { repeat: true }
|
T[K] extends { repeat: true }
|
||||||
? ProtoFieldReturnType<T[K], E>[]
|
? ProtoFieldReturnType<T[K], E>[]
|
||||||
: ProtoFieldReturnType<T[K], E>
|
: ProtoFieldReturnType<T[K], E>
|
||||||
}
|
}
|
||||||
|
|
||||||
type OptionalFieldsBaseType<T extends unknown, E extends boolean> = {
|
type OptionalFieldsBaseType<T, E extends boolean> = {
|
||||||
[K in keyof T as T[K] extends { optional: true } ? LowerCamelCase<K & string> : never]?:
|
[K in keyof T as T[K] extends { optional: true } ? LowerCamelCase<K & string> : never]?:
|
||||||
T[K] extends { repeat: true }
|
T[K] extends { repeat: true }
|
||||||
? ProtoFieldReturnType<T[K], E>[]
|
? ProtoFieldReturnType<T[K], E>[]
|
||||||
: ProtoFieldReturnType<T[K], E>
|
: ProtoFieldReturnType<T[K], E>
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequiredFieldsType<T extends unknown, E extends boolean> = E extends true ? Partial<RequiredFieldsBaseType<T, E>> : RequiredFieldsBaseType<T, E>;
|
type RequiredFieldsType<T, E extends boolean> = E extends true ? Partial<RequiredFieldsBaseType<T, E>> : RequiredFieldsBaseType<T, E>;
|
||||||
|
|
||||||
type OptionalFieldsType<T extends unknown, E extends boolean> = E extends true ? Partial<OptionalFieldsBaseType<T, E>> : OptionalFieldsBaseType<T, E>;
|
type OptionalFieldsType<T, E extends boolean> = E extends true ? Partial<OptionalFieldsBaseType<T, E>> : OptionalFieldsBaseType<T, E>;
|
||||||
|
|
||||||
type NapProtoStructType<T extends unknown, E extends boolean> = RequiredFieldsType<T, E> & OptionalFieldsType<T, E>;
|
type NapProtoStructType<T, E extends boolean> = RequiredFieldsType<T, E> & OptionalFieldsType<T, E>;
|
||||||
|
|
||||||
export type NapProtoEncodeStructType<T extends unknown> = NapProtoStructType<T, true>;
|
export type NapProtoEncodeStructType<T> = NapProtoStructType<T, true>;
|
||||||
|
|
||||||
export type NapProtoDecodeStructType<T extends unknown> = NapProtoStructType<T, false>;
|
export type NapProtoDecodeStructType<T> = NapProtoStructType<T, false>;
|
||||||
|
|
||||||
const NapProtoMsgCache = new Map<ProtoMessageType, MessageType<NapProtoStructType<ProtoMessageType, boolean>>>();
|
const NapProtoMsgCache = new Map<ProtoMessageType, MessageType<NapProtoStructType<ProtoMessageType, boolean>>>();
|
||||||
|
|
||||||
|
@@ -12,13 +12,13 @@ import {
|
|||||||
import { GeneralCallResult } from '@/core/services/common';
|
import { GeneralCallResult } from '@/core/services/common';
|
||||||
|
|
||||||
export interface NodeIKernelGroupService {
|
export interface NodeIKernelGroupService {
|
||||||
// --->
|
// --->
|
||||||
// 待启用 For Next Version 3.2.0
|
// 待启用 For Next Version 3.2.0
|
||||||
// isTroopMember ? 0 : 111
|
// isTroopMember ? 0 : 111
|
||||||
getGroupMemberMaxNum(groupCode: string, serviceType: number): Promise<unknown>;
|
getGroupMemberMaxNum(groupCode: string, serviceType: number): Promise<unknown>;
|
||||||
|
|
||||||
getAllGroupPrivilegeFlag(troopUinList: string[], serviceType: number): Promise<unknown>;
|
getAllGroupPrivilegeFlag(troopUinList: string[], serviceType: number): Promise<unknown>;
|
||||||
// <---
|
// <---
|
||||||
getGroupExt0xEF0Info(enableGroupCodes: string[], bannedGroupCodes: string[], filter: GroupExt0xEF0InfoFilter, forceFetch: boolean):
|
getGroupExt0xEF0Info(enableGroupCodes: string[], bannedGroupCodes: string[], filter: GroupExt0xEF0InfoFilter, forceFetch: boolean):
|
||||||
Promise<GeneralCallResult & { result: { groupExtInfos: Map<string, any> } }>;
|
Promise<GeneralCallResult & { result: { groupExtInfos: Map<string, any> } }>;
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ export interface NodeIKernelGroupService {
|
|||||||
}
|
}
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
setHeader(uid: string, path: string): unknown;
|
setHeader(uid: string, path: string): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
addKernelGroupListener(listener: NodeIKernelGroupListener): number;
|
addKernelGroupListener(listener: NodeIKernelGroupListener): number;
|
||||||
|
|
||||||
|
@@ -172,7 +172,7 @@ export interface NodeIKernelMsgService {
|
|||||||
msgList: RawMessage[]
|
msgList: RawMessage[]
|
||||||
}>;
|
}>;
|
||||||
//@deprecated
|
//@deprecated
|
||||||
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & {
|
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, isReverseOrder: boolean): Promise<GeneralCallResult & {
|
||||||
msgList: RawMessage[]
|
msgList: RawMessage[]
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
@@ -186,27 +186,29 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown;
|
// 下面的msgid全部不真实
|
||||||
|
getSourceOfReplyMsg(peer: Peer, msgId: string, sourceSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getSourceOfReplyMsgV2(peer: Peer, RootMsgId: string, ReplyMsgId: string): unknown;
|
//用法和聊天记录一样
|
||||||
|
getSourceOfReplyMsgV2(peer: Peer, rootMsgId: string, replyMsgId: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown;
|
getMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getSourceOfReplyMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown;
|
getSourceOfReplyMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string, replyMsgId: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgsByTypeFilter(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilter: {
|
getMsgsByTypeFilter(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilter: {
|
||||||
type: number,
|
type: number,
|
||||||
subtype: Array<number>
|
subtype: Array<number>
|
||||||
}): unknown;
|
}): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgsByTypeFilters(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilters: Array<{
|
getMsgsByTypeFilters(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilters: Array<{
|
||||||
type: number,
|
type: number,
|
||||||
subtype: Array<number>
|
subtype: Array<number>
|
||||||
}>): unknown;
|
}>): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgWithAbstractByFilterParam(...args: unknown[]): unknown;
|
getMsgWithAbstractByFilterParam(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
queryMsgsWithFilter(...args: unknown[]): unknown;
|
queryMsgsWithFilter(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
//queryMsgsWithFilterVer2(MsgId: string, MsgTime: string, param: QueryMsgsParams): Promise<unknown>;
|
//queryMsgsWithFilterVer2(MsgId: string, MsgTime: string, param: QueryMsgsParams): Promise<unknown>;
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ export async function NCoreInitFramework(
|
|||||||
online: true,
|
online: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger) as any);
|
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
||||||
});
|
});
|
||||||
// 过早进入会导致addKernelMsgListener等Listener添加失败
|
// 过早进入会导致addKernelMsgListener等Listener添加失败
|
||||||
// await sleep(2500);
|
// await sleep(2500);
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import {ActionName} from '../types';
|
import { ActionName } from '../types';
|
||||||
import {FromSchema, JSONSchema} from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import {GetPacketStatusDepends} from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import {MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams} from "@/core/packet/entities/miniApp";
|
import { MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams } from "@/core/packet/entities/miniApp";
|
||||||
import {MiniAppInfo, MiniAppInfoHelper} from "@/core/packet/helper/miniAppHelper";
|
import { MiniAppInfo, MiniAppInfoHelper } from "@/core/packet/helper/miniAppHelper";
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@@ -11,21 +11,21 @@ const SchemaData = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
enum: ['bili', 'weibo']
|
enum: ['bili', 'weibo']
|
||||||
},
|
},
|
||||||
title: {type: 'string'},
|
title: { type: 'string' },
|
||||||
desc: {type: 'string'},
|
desc: { type: 'string' },
|
||||||
picUrl: {type: 'string'},
|
picUrl: { type: 'string' },
|
||||||
jumpUrl: {type: 'string'},
|
jumpUrl: { type: 'string' },
|
||||||
iconUrl: {type: 'string'},
|
iconUrl: { type: 'string' },
|
||||||
sdkId: {type: 'string'},
|
sdkId: { type: 'string' },
|
||||||
appId: {type: 'string'},
|
appId: { type: 'string' },
|
||||||
scene: {type: ['number', 'string']},
|
scene: { type: ['number', 'string'] },
|
||||||
templateType: {type: ['number', 'string']},
|
templateType: { type: ['number', 'string'] },
|
||||||
businessType: {type: ['number', 'string']},
|
businessType: { type: ['number', 'string'] },
|
||||||
verType: {type: ['number', 'string']},
|
verType: { type: ['number', 'string'] },
|
||||||
shareType: {type: ['number', 'string']},
|
shareType: { type: ['number', 'string'] },
|
||||||
versionId: {type: 'string'},
|
versionId: { type: 'string' },
|
||||||
withShareTicket: {type: ['number', 'string']},
|
withShareTicket: { type: ['number', 'string'] },
|
||||||
rawArkData: {type: ['boolean', 'string']}
|
rawArkData: { type: ['boolean', 'string'] }
|
||||||
},
|
},
|
||||||
oneOf: [
|
oneOf: [
|
||||||
{
|
{
|
||||||
@@ -75,11 +75,11 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
|||||||
versionId: versionId,
|
versionId: versionId,
|
||||||
withShareTicket: +withShareTicket
|
withShareTicket: +withShareTicket
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
const arkData = await this.core.apis.PacketApi.sendMiniAppShareInfoReq(reqParam);
|
const arkData = await this.core.apis.PacketApi.sendMiniAppShareInfoReq(reqParam);
|
||||||
return {
|
return {
|
||||||
data: Boolean(payload.rawArkData) ? arkData : MiniAppInfoHelper.RawToSend(arkData)
|
data: payload.rawArkData ? arkData : MiniAppInfoHelper.RawToSend(arkData)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,11 +38,10 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
|||||||
throw `头像${payload.file}设置失败,api无返回`;
|
throw `头像${payload.file}设置失败,api无返回`;
|
||||||
}
|
}
|
||||||
// log(`头像设置返回:${JSON.stringify(ret)}`)
|
// log(`头像设置返回:${JSON.stringify(ret)}`)
|
||||||
// @ts-ignore
|
if (ret.result as number == 1004022) {
|
||||||
if (ret['result'] == 1004022) {
|
|
||||||
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
|
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
|
||||||
} else if (ret['result'] != 0) {
|
} else if (ret.result != 0) {
|
||||||
throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
|
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
|
@@ -5,9 +5,11 @@ import { promises as fs } from 'fs';
|
|||||||
import { decode } from 'silk-wasm';
|
import { decode } from 'silk-wasm';
|
||||||
const FFMPEG_PATH = process.env.FFMPEG_PATH || 'ffmpeg';
|
const FFMPEG_PATH = process.env.FFMPEG_PATH || 'ffmpeg';
|
||||||
|
|
||||||
interface Payload extends GetFilePayload {
|
const out_format = ['mp3' , 'amr' , 'wma' , 'm4a' , 'spx' , 'ogg' , 'wav' , 'flac'];
|
||||||
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac';
|
|
||||||
}
|
type Payload = {
|
||||||
|
out_format : string
|
||||||
|
} & GetFilePayload
|
||||||
|
|
||||||
export default class GetRecord extends GetFileBase {
|
export default class GetRecord extends GetFileBase {
|
||||||
actionName = ActionName.GetRecord;
|
actionName = ActionName.GetRecord;
|
||||||
@@ -17,12 +19,19 @@ export default class GetRecord extends GetFileBase {
|
|||||||
if (payload.out_format && typeof payload.out_format === 'string') {
|
if (payload.out_format && typeof payload.out_format === 'string') {
|
||||||
const inputFile = res.file;
|
const inputFile = res.file;
|
||||||
if (!inputFile) throw new Error('file not found');
|
if (!inputFile) throw new Error('file not found');
|
||||||
|
if (!out_format.includes(payload.out_format)) {
|
||||||
|
throw new Error('转换失败 out_format 字段可能格式不正确');
|
||||||
|
}
|
||||||
const pcmFile = `${inputFile}.pcm`;
|
const pcmFile = `${inputFile}.pcm`;
|
||||||
const outputFile = `${inputFile}.${payload.out_format}`;
|
const outputFile = `${inputFile}.${payload.out_format}`;
|
||||||
try {
|
try {
|
||||||
await fs.access(inputFile);
|
await fs.access(inputFile);
|
||||||
await this.decodeFile(inputFile, pcmFile);
|
try {
|
||||||
await this.convertFile(pcmFile, outputFile, payload.out_format);
|
await fs.access(outputFile);
|
||||||
|
} catch (error) {
|
||||||
|
await this.decodeFile(inputFile, pcmFile);
|
||||||
|
await this.convertFile(pcmFile, outputFile, payload.out_format);
|
||||||
|
}
|
||||||
const base64Data = await fs.readFile(outputFile, { encoding: 'base64' });
|
const base64Data = await fs.readFile(outputFile, { encoding: 'base64' });
|
||||||
res.file = outputFile;
|
res.file = outputFile;
|
||||||
res.url = outputFile;
|
res.url = outputFile;
|
||||||
@@ -48,7 +57,8 @@ export default class GetRecord extends GetFileBase {
|
|||||||
|
|
||||||
private convertFile(inputFile: string, outputFile: string, format: string): Promise<void> {
|
private convertFile(inputFile: string, outputFile: string, format: string): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const ffmpeg = spawn(FFMPEG_PATH, ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, outputFile]);
|
const params = format === 'amr' ? ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, '-ar', '8000', '-b:a', '12.2k', outputFile] : ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, outputFile];
|
||||||
|
const ffmpeg = spawn(FFMPEG_PATH, params);
|
||||||
|
|
||||||
ffmpeg.on('close', (code) => {
|
ffmpeg.on('close', (code) => {
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
@@ -63,4 +73,4 @@ export default class GetRecord extends GetFileBase {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,11 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
|||||||
if (!uid) uid = extendData.detail.uid;
|
if (!uid) uid = extendData.detail.uid;
|
||||||
const info = (await this.core.apis.UserApi.getUserDetailInfo(uid));
|
const info = (await this.core.apis.UserApi.getUserDetailInfo(uid));
|
||||||
return {
|
return {
|
||||||
|
...extendData.detail.simpleInfo.coreInfo,
|
||||||
|
...extendData.detail.commonExt ?? {},
|
||||||
|
...extendData.detail.simpleInfo.baseInfo,
|
||||||
|
...extendData.detail.simpleInfo.relationFlags ?? {},
|
||||||
|
...extendData.detail.simpleInfo.status ?? {},
|
||||||
user_id: parseInt(extendData.detail.uin) ?? 0,
|
user_id: parseInt(extendData.detail.uin) ?? 0,
|
||||||
uid: info.uid ?? uid,
|
uid: info.uid ?? uid,
|
||||||
nickname: extendData.detail.simpleInfo.coreInfo.nick,
|
nickname: extendData.detail.simpleInfo.coreInfo.nick,
|
||||||
@@ -33,7 +38,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
|||||||
qqLevel: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? info.qqLevel),
|
qqLevel: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? info.qqLevel),
|
||||||
sex: OB11Entities.sex(extendData.detail.simpleInfo.baseInfo.sex) ?? OB11UserSex.unknown,
|
sex: OB11Entities.sex(extendData.detail.simpleInfo.baseInfo.sex) ?? OB11UserSex.unknown,
|
||||||
long_nick: extendData.detail.simpleInfo.baseInfo.longNick ?? info.longNick,
|
long_nick: extendData.detail.simpleInfo.baseInfo.longNick ?? info.longNick,
|
||||||
reg_time: extendData.detail.commonExt.regTime ?? info.regTime,
|
reg_time: extendData.detail.commonExt?.regTime ?? info.regTime,
|
||||||
is_vip: extendData.detail.simpleInfo.vasInfo?.svipFlag,
|
is_vip: extendData.detail.simpleInfo.vasInfo?.svipFlag,
|
||||||
is_years_vip: extendData.detail.simpleInfo.vasInfo?.yearVipFlag,
|
is_years_vip: extendData.detail.simpleInfo.vasInfo?.yearVipFlag,
|
||||||
vip_level: extendData.detail.simpleInfo.vasInfo?.vipLevel,
|
vip_level: extendData.detail.simpleInfo.vasInfo?.vipLevel,
|
||||||
|
@@ -31,15 +31,15 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
|
|||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path) as any;
|
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw `头像${payload.file}设置失败,api无返回`;
|
throw `头像${payload.file}设置失败,api无返回`;
|
||||||
}
|
}
|
||||||
if (ret['result'] == 1004022) {
|
if (ret.result as number == 1004022) {
|
||||||
throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
|
throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
|
||||||
} else if (ret['result'] != 0) {
|
} else if (ret.result != 0) {
|
||||||
throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
|
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -236,12 +236,11 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
message: RawMessage | null,
|
message: RawMessage | null,
|
||||||
res_id?: string
|
res_id?: string
|
||||||
}> {
|
}> {
|
||||||
let returnMsg: RawMessage | undefined, res_id: string | undefined;
|
|
||||||
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, messageNodes, source, news, summary, prompt);
|
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, messageNodes, source, news, summary, prompt);
|
||||||
res_id = uploadReturnData?.res_id;
|
const res_id = uploadReturnData?.res_id;
|
||||||
const finallySendElements = uploadReturnData?.finallySendElements;
|
const finallySendElements = uploadReturnData?.finallySendElements;
|
||||||
if (!finallySendElements) throw Error('转发消息失败,生成节点为空');
|
if (!finallySendElements) throw Error('转发消息失败,生成节点为空');
|
||||||
returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined);
|
const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined);
|
||||||
return { message: returnMsg ?? null, res_id };
|
return { message: returnMsg ?? null, res_id };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +275,6 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
logger.logError.bind(this.core.context.logger)('子消息中包含非node消息 跳过不合法部分');
|
logger.logError.bind(this.core.context.logger)('子消息中包含非node消息 跳过不合法部分');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
|
||||||
const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
|
const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
|
||||||
if (nodeMsg) {
|
if (nodeMsg) {
|
||||||
nodeMsgIds.push(nodeMsg.message!.msgId);
|
nodeMsgIds.push(nodeMsg.message!.msgId);
|
||||||
|
@@ -24,7 +24,6 @@ import {
|
|||||||
OB11MessageData,
|
OB11MessageData,
|
||||||
OB11MessageDataType,
|
OB11MessageDataType,
|
||||||
OB11MessageFileBase,
|
OB11MessageFileBase,
|
||||||
OB11MessageForward,
|
|
||||||
} from '@/onebot';
|
} from '@/onebot';
|
||||||
import { OB11Entities } from '@/onebot/entities';
|
import { OB11Entities } from '@/onebot/entities';
|
||||||
import { EventType } from '@/onebot/event/OB11BaseEvent';
|
import { EventType } from '@/onebot/event/OB11BaseEvent';
|
||||||
@@ -218,20 +217,34 @@ export class OneBotMsgApi {
|
|||||||
if (records.peerUin === '284840486' || records.peerUin === '1094950020') {
|
if (records.peerUin === '284840486' || records.peerUin === '1094950020') {
|
||||||
return createReplyData(records.msgId);
|
return createReplyData(records.msgId);
|
||||||
}
|
}
|
||||||
let replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr])).msgList;
|
let replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, records.msgTime, [element.senderUidStr])).msgList;
|
||||||
let replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
let replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
||||||
|
|
||||||
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
// 我猜测可能是时间参数未对上 导致找不到引用消息 或者msgList 存在问题
|
this.core.context.logger.logError.bind(this.core.context.logger)(
|
||||||
this.core.context.logger.logWarn.bind(this.core.context.logger)(
|
'筛选结果,筛选消息失败,将使用Fallback-1 Seq: ',
|
||||||
'初次筛选消息失败,获取不到引用的消息 Seq:',
|
element.replayMsgSeq,
|
||||||
|
',消息长度:',
|
||||||
|
replyMsgList.length
|
||||||
|
);
|
||||||
|
replyMsgList = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer, element.replayMsgSeq, 1, true, true)).msgList;
|
||||||
|
replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
|
this.core.context.logger.logWarn.bind(this.core.context.logger)(
|
||||||
|
'筛选消息失败,将使用Fallback-2 Seq:',
|
||||||
element.replayMsgSeq,
|
element.replayMsgSeq,
|
||||||
',消息长度:',
|
',消息长度:',
|
||||||
replyMsgList.length
|
replyMsgList.length
|
||||||
);
|
);
|
||||||
// 再次筛选
|
|
||||||
replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV3(peer, element.replayMsgSeq, [element.senderUidStr])).msgList;
|
replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV3(peer, element.replayMsgSeq, [element.senderUidStr])).msgList;
|
||||||
replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 丢弃该消息段
|
||||||
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
this.core.context.logger.logError.bind(this.core.context.logger)(
|
this.core.context.logger.logError.bind(this.core.context.logger)(
|
||||||
'最终筛选结果,筛选消息失败,获取不到引用的消息 Seq: ',
|
'最终筛选结果,筛选消息失败,获取不到引用的消息 Seq: ',
|
||||||
@@ -327,11 +340,11 @@ export class OneBotMsgApi {
|
|||||||
},
|
},
|
||||||
|
|
||||||
multiForwardMsgElement: async (_, msg) => {
|
multiForwardMsgElement: async (_, msg) => {
|
||||||
const message_data: OB11MessageForward = {
|
// const message_data: OB11MessageForward = {
|
||||||
data: {} as any,
|
// data: {} as any,
|
||||||
type: OB11MessageDataType.forward,
|
// type: OB11MessageDataType.forward,
|
||||||
};
|
// };
|
||||||
message_data.data.id = msg.msgId;
|
// message_data.data.id = msg.msgId;
|
||||||
const parentMsgPeer = msg.parentMsgPeer ?? {
|
const parentMsgPeer = msg.parentMsgPeer ?? {
|
||||||
chatType: msg.chatType,
|
chatType: msg.chatType,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
@@ -743,9 +756,12 @@ export class OneBotMsgApi {
|
|||||||
async (element) => {
|
async (element) => {
|
||||||
for (const key in element) {
|
for (const key in element) {
|
||||||
if (keyCanBeParsed(key, this.rawToOb11Converters) && element[key]) {
|
if (keyCanBeParsed(key, this.rawToOb11Converters) && element[key]) {
|
||||||
const parsedElement = await this.rawToOb11Converters[key]?.(
|
const converters = this.rawToOb11Converters[key] as (
|
||||||
// eslint-disable-next-line
|
element: Exclude<MessageElement[keyof RawToOb11Converters], null | undefined>,
|
||||||
// @ts-ignore
|
msg: RawMessage,
|
||||||
|
elementWrapper: MessageElement,
|
||||||
|
) => PromiseLike<OB11MessageData | null>;
|
||||||
|
const parsedElement = await converters?.(
|
||||||
element[key],
|
element[key],
|
||||||
msg,
|
msg,
|
||||||
element,
|
element,
|
||||||
@@ -794,9 +810,11 @@ export class OneBotMsgApi {
|
|||||||
if (ignoreTypes.includes(sendMsg.type)) {
|
if (ignoreTypes.includes(sendMsg.type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const callResult = this.ob11ToRawConverters[sendMsg.type](
|
const converter = this.ob11ToRawConverters[sendMsg.type] as (
|
||||||
// eslint-disable-next-line
|
sendMsg: Extract<OB11MessageData, { type: OB11MessageData['type'] }>,
|
||||||
// @ts-ignore
|
context: MessageContext,
|
||||||
|
) => Promise<SendMessageElement | undefined>;
|
||||||
|
const callResult = converter(
|
||||||
sendMsg,
|
sendMsg,
|
||||||
{ peer, deleteAfterSentFiles },
|
{ peer, deleteAfterSentFiles },
|
||||||
)?.catch(undefined);
|
)?.catch(undefined);
|
||||||
|
@@ -68,13 +68,13 @@ export function encodeCQCode(data: OB11MessageData) {
|
|||||||
|
|
||||||
let result = '[CQ:' + data.type;
|
let result = '[CQ:' + data.type;
|
||||||
for (const name in data.data) {
|
for (const name in data.data) {
|
||||||
const value = (data.data as any)[name];
|
const value = (data.data as Record<string, unknown>)[name];
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const text = value.toString();
|
const text = value?.toString();
|
||||||
result += `,${name}=${CQCodeEscape(text)}`;
|
if (text) result += `,${name}=${CQCodeEscape(text)}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If it can't be converted, skip this name-value pair
|
// If it can't be converted, skip this name-value pair
|
||||||
}
|
}
|
||||||
|
@@ -341,7 +341,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.context.session.getMsgService().addKernelMsgListener(
|
this.context.session.getMsgService().addKernelMsgListener(
|
||||||
proxiedListenerOf(msgListener, this.context.logger) as any,
|
proxiedListenerOf(msgListener, this.context.logger),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.context.session.getBuddyService().addKernelBuddyListener(
|
this.context.session.getBuddyService().addKernelBuddyListener(
|
||||||
proxiedListenerOf(buddyListener, this.context.logger) as any,
|
proxiedListenerOf(buddyListener, this.context.logger),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,9 +64,9 @@ export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.app.use((req, res, next) => this.authorize(this.token, req, res, next));
|
this.app.use((req, res, next) => this.authorize(this.token, req, res, next));
|
||||||
// @ts-ignore
|
this.app.use(async (req, res, _) => {
|
||||||
this.app.use((req, res) => this.handleRequest(req, res));
|
await this.handleRequest(req, res);
|
||||||
|
});
|
||||||
this.server.listen(this.port, () => {
|
this.server.listen(this.port, () => {
|
||||||
this.core.context.logger.log(`[OneBot] [HTTP Server Adapter] Start On Port ${this.port}`);
|
this.core.context.logger.log(`[OneBot] [HTTP Server Adapter] Start On Port ${this.port}`);
|
||||||
});
|
});
|
||||||
|
@@ -165,7 +165,7 @@ export async function NCoreInitShell() {
|
|||||||
logger.logError.bind(logger)('[Core] [Login] Login Error , ErrInfo: ', args);
|
logger.logError.bind(logger)('[Core] [Login] Login Error , ErrInfo: ', args);
|
||||||
};
|
};
|
||||||
|
|
||||||
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger) as any);
|
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
||||||
const isConnect = loginService.connect();
|
const isConnect = loginService.connect();
|
||||||
if (!isConnect) {
|
if (!isConnect) {
|
||||||
logger.logError.bind(logger)('核心登录服务连接失败!');
|
logger.logError.bind(logger)('核心登录服务连接失败!');
|
||||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'<span id="napcat-update-title">Napcat</span>',
|
'<span id="napcat-update-title">Napcat</span>',
|
||||||
void 0,
|
void 0,
|
||||||
SettingButton("V3.3.22", "napcat-update-button", "secondary")
|
SettingButton("V3.4.0", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Reference in New Issue
Block a user