chore: 1.8.4

This commit is contained in:
手瓜一十雪
2024-08-09 10:48:13 +08:00
parent b46459de5f
commit 7b10d75aeb
59 changed files with 193 additions and 156 deletions

View File

@@ -4,11 +4,9 @@
## 项目介绍
NapCatQQ 是基于 PC NTQQ 本体实现一套无头 Bot 框架。
NapCatQQ 是基于 PC NTQQ 本体实现一套无头 Bot 框架。
NapCat 意为「瞌睡猫,像睡着了一样在后台低占用运行的无需 GUI 界面的 NTQQ。
项目的 [v2](https://github.com/NapNeko/NapCatQQ/tree/v2) 重构正在进行中,敬请关注。
名字寓意 瞌睡猫QQ像睡着了一样在后台低占用运行的无需GUI界面的NTQQ。
## 如何使用
@@ -16,14 +14,14 @@ NapCat 意为「瞌睡猫」,像睡着了一样在后台低占用运行的、
**首次使用** 请务必前往 [官方文档](https://napneko.github.io/) 查看使用文档与教程
## 项目声明
* 请不要在无关地方宣传 NapCatQQ本项目只是用于学习 node 相关知识,切勿用于违法用途
* 请不要在无关地方宣传NapCatQQ本项目只是用于学习 node 相关知识,切勿用于违法用途
* NapCat 不会收集用户隐私信息,但是未来可能会为了更好的利于 NapCat 的优化会收集一些设备信息,如 CPU 架构,系统版本等
* NapCat 不会收集用户隐私信息,但是未来可能会为了更好的利于 NapCat 的优化会收集一些设备信息,如 cpu 架构,系统版本等
## 相关链接
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
## 鸣谢名单

View File

@@ -0,0 +1,12 @@
# v1.8.4
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
## 启动的方式
Way03/Way05
## 新增与调整
1. 支持主动临时消息
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "1.8.3",
"version": "1.8.4",
"scripts": {
"watch:dev": "vite --mode development",
"watch:prod": "vite --mode production",
@@ -53,7 +53,6 @@
},
"dependencies": {
"ajv": "^8.13.0",
"strtok3":"8.0.1",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"cors": "^2.8.5",

View File

@@ -86,5 +86,5 @@ where wt >nul 2>nul
if %errorlevel% equ 0 (
wt "cmd" /c "%QQPath%" --enable-logging %*
) else (
%QQPath%" --enable-logging %*
"%QQPath%" --enable-logging %*
)

View File

@@ -39,7 +39,7 @@ export function getAppidV2(): { appid: string, qua: string } {
}
}
catch (e) {
log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
log('[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常');
}
// 以下是兜底措施
log(`[QQ版本兼容性检测] ${getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);

View File

@@ -220,7 +220,7 @@ export class NTQQGroupApi {
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
return napCatCore.session.getGroupService().uploadGroupBulletinPic(GroupCode, _Pskey, imageurl);
}
static async handleGroupRequest(flag: string, operateType: GroupRequestOperateTypes, reason?: string) {
static async handleGroupRequest(flag: string , operateType: GroupRequestOperateTypes, reason?: string) {
let flagitem = flag.split('|');
let groupCode = flagitem[0];
let seq = flagitem[1];

View File

@@ -1,8 +1,8 @@
import { GetFileListParam, Peer, RawMessage, SendMessageElement, SendMsgElementConstructor } from '@/core/entities';
import { friends, groups, selfInfo } from '@/core/data';
import { ChatType, ChatType2, GetFileListParam, Peer, RawMessage, SendMessageElement, SendMsgElementConstructor } from '@/core/entities';
import { friends, getGroupMember, groups, selfInfo } from '@/core/data';
import { log, logWarn } from '@/common/utils/log';
import { sleep } from '@/common/utils/helper';
import { napCatCore, NTQQUserApi } from '@/core';
import { napCatCore, NTQQGroupApi, NTQQUserApi } from '@/core';
import { onGroupFileInfoUpdateParamType } from '@/core/listeners';
import { GeneralCallResult } from '@/core/services/common';
import { MessageUnique } from '../../../common/utils/MessageUnique';
@@ -71,6 +71,29 @@ export class NTQQMsgApi {
static async FetchLongMsg(peer: Peer, msgId: string) {
return napCatCore.session.getMsgService().fetchLongMsg(peer, msgId);
}
static async getTempChatInfo(chatType: ChatType2, peerUid: string) {
return napCatCore.session.getMsgService().getTempChatInfo(chatType, peerUid);
}
static async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) {
//By Jadx/Ida Mlikiowa
let TempGameSession = {
nickname: "",
gameAppId: "",
selfTinyId: "",
peerRoleId: "",
peerOpenId: "",
};
return napCatCore.session.getMsgService().prepareTempChat({
chatType: ChatType2.KCHATTYPETEMPC2CFROMGROUP,
peerUid: toUserUid,
peerNickname: nickname,
fromGroupCode: GroupCode,
sig: "",
selfPhone: "",
selfUid: selfInfo.uid,
gameSession: TempGameSession
});
}
static 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
@@ -97,7 +120,7 @@ export class NTQQMsgApi {
return napCatCore.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId);
}
static async ForwardMsg(peer: Peer, msgIds: string[]) {
return napCatCore.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map());
return napCatCore.session.getMsgService().forwardMsg(msgIds, peer, [peer], []);
}
static async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
@@ -137,6 +160,16 @@ export class NTQQMsgApi {
});
return ret;
}
/**
*
* @deprecated 从9.9.15-26702版本开始该接口已经废弃请使用getMsgsEx
* @param peer
* @param seq
* @param count
* @param desc
* @param z
* @returns
*/
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
return await napCatCore.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
}
@@ -172,6 +205,9 @@ export class NTQQMsgApi {
}, msgIds);
}
static async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
if (peer.chatType === ChatType.temp) {
//await NTQQMsgApi.PrepareTempChat().then().catch();
}
function generateMsgId() {
const timestamp = Math.floor(Date.now() / 1000);
const random = Math.floor(Math.random() * Math.pow(2, 32));
@@ -225,7 +261,32 @@ export class NTQQMsgApi {
}
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
//唉? !我有个想法
let msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime());
function generateMsgId() {
const timestamp = Math.floor(Date.now() / 1000);
const random = Math.floor(Math.random() * Math.pow(2, 32));
const buffer = Buffer.alloc(8);
buffer.writeUInt32BE(timestamp, 0);
buffer.writeUInt32BE(random, 4);
const msgId = BigInt("0x" + buffer.toString('hex')).toString();
return msgId;
}
// 此处有采用Hack方法 利用数据返回正确得到对应消息
// 与之前 Peer队列 MsgSeq队列 真正的MsgId并发不同
// 谨慎采用 目前测试暂无问题 Developer.Mlikiowa
let msgId: string;
try {
msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime());
} catch (error) {
//if (!napCatCore.session.getMsgService()['generateMsgUniqueId'])
//兜底识别策略V2
msgId = generateMsgId();
}
if (peer.chatType === ChatType.temp && peer.guildId && peer.guildId !== '') {
let member = await getGroupMember(peer.guildId, peer.peerUid!);
if(member){
await NTQQMsgApi.PrepareTempChat(peer.peerUid,peer.guildId,member.nick);
}
}
peer.guildId = msgId;
let data = await NTEventDispatch.CallNormalEvent<
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
@@ -268,7 +329,7 @@ export class NTQQMsgApi {
return NTEventDispatch.CallNoListenerEvent<() => string>('NodeIKernelMsgService/getServerTime', 5000);
}
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
return napCatCore.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map());
return napCatCore.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], []);
}
static async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage> {
const msgInfos = msgIds.map(id => {

View File

@@ -80,9 +80,6 @@ export async function getGroupMember(groupQQ: string | number, memberUinOrUid: s
}
return member;
}
// 考虑优化 移入QQ缓存或使用Api直接获取
export const tempGroupCodeMap: Record<string, string> = {}; // peerUid => 群号
// 保留 需要频繁读写
export const stat = {
packet_received: 0,

View File

@@ -12,6 +12,21 @@ export interface QueryMsgsParams {
isReverseOrder: boolean,
isIncludeCurrent: boolean
}
export interface TmpChatInfoApi {
errMsg: string;
result: number;
tmpChatInfo?: TmpChatInfo;
}
export interface TmpChatInfo {
chatType: number;
fromNick: string;
groupCode: string;
peerUid: string;
sessionType: number;
sig: string;
}
export interface NodeIKernelMsgService {
generateMsgUniqueId(chatType: number, time: string): string;
@@ -97,8 +112,8 @@ export interface NodeIKernelMsgService {
recallMsg(...args: unknown[]): unknown;
reeditRecallMsg(...args: unknown[]): unknown;
forwardMsg(...args: unknown[]): Promise<GeneralCallResult>;
//调用请检查除开commentElements其余参数不能为null
forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult>;
forwardMsgWithComment(...args: unknown[]): unknown;
@@ -156,6 +171,7 @@ export interface NodeIKernelMsgService {
getAioFirstViewLatestMsgs(peer: Peer, num: number): unknown;
//deprecated 从9.9.15-26702版本开始该接口已经废弃请使用getMsgsEx
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>;
getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & {
@@ -608,7 +624,7 @@ export interface NodeIKernelMsgService {
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>;
//chattype,uid->Promise<any>
getTempChatInfo(ChatType: number, Uid: string): unknown;
getTempChatInfo(ChatType: number, Uid: string): Promise<TmpChatInfoApi>;
setContactLocalTop(...args: unknown[]): unknown;

4
src/nwebui/Readme.md Normal file
View File

@@ -0,0 +1,4 @@
# NewWebui
基于Vue3实现的现代化轻量化NapCat管理面板
## 进度
画饼

View File

@@ -2,7 +2,6 @@
import { NTQQCollectionApi } from '@/core/apis/collection';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { selfInfo } from '@/core/data';

View File

@@ -1,16 +1,12 @@
import BaseAction from '../BaseAction';
// import * as ntqqApi from "../../../ntqqapi/api";
import {
NTQQMsgApi,
NTQQFriendApi,
NTQQGroupApi,
NTQQUserApi,
NTQQFileApi,
// NTQQFileCacheApi,
} from '@/core';
import { ActionName } from '../types';
import { log, logDebug } from '@/common/utils/log';
interface Payload {
method: string,
args: any[],
@@ -20,12 +16,8 @@ export default class Debug extends BaseAction<Payload, any> {
actionName = ActionName.Debug;
protected async _handle(payload: Payload): Promise<any> {
//logDebug('debug call ntqq api', payload);
const ntqqApi = [NTQQMsgApi, NTQQFriendApi, NTQQGroupApi, NTQQUserApi, NTQQFileApi,
// NTQQFileCacheApi,
];
const ntqqApi = [NTQQMsgApi, NTQQFriendApi, NTQQGroupApi, NTQQUserApi, NTQQFileApi,];
for (const ntqqApiClass of ntqqApi) {
// logDebug('ntqqApiClass', ntqqApiClass);
const method = (<any>ntqqApiClass)[payload.method];
if (method) {
const result = method(...payload.args);
@@ -36,8 +28,5 @@ export default class Debug extends BaseAction<Payload, any> {
}
}
throw `${payload.method}方法 不存在`;
// const info = await NTQQApi.getUserDetailInfo(friends[0].uid);
// return info
}
}

View File

@@ -24,9 +24,9 @@ export class FetchEmojioLike extends BaseAction<Payload, any> {
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if(!msgIdPeer) throw new Error('消息不存在');
if (!msgIdPeer) throw new Error('消息不存在');
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count);
const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, payload.count);
return ret;
}
}

View File

@@ -2,9 +2,7 @@
import { NTQQCollectionApi } from '@/core/apis/collection';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { selfInfo } from '@/core/data';
const SchemaData = {
type: 'object',

View File

@@ -5,7 +5,6 @@ export class GetRobotUinRange extends BaseAction<void, Array<any>> {
actionName = ActionName.GetRobotUinRange;
protected async _handle(payload: void) {
// console.log(await NTQQUserApi.getRobotUinRange());
return await NTQQUserApi.getRobotUinRange();
}
}

View File

@@ -20,7 +20,7 @@ export class OCRImage extends BaseAction<Payload, any> {
actionName = ActionName.OCRImage;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
const { path, isLocal, errMsg,success } = (await uri2local(payload.image));
const { path, isLocal, errMsg, success } = (await uri2local(payload.image));
if (!success) {
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
}

View File

@@ -1,10 +1,8 @@
import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import * as fs from 'node:fs';
import { NTQQUserApi } from '@/core/apis/user';
import { checkFileReceived, uri2local } from '@/common/utils/file';
import { NTQQGroupApi } from '@/core';
// import { log } from "../../../common/utils";
interface Payload {
file: string,

View File

@@ -1,4 +1,3 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';

View File

@@ -1,5 +1,5 @@
import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// 设置在线状态
@@ -20,12 +20,6 @@ export class SetOnlineStatus extends BaseAction<Payload, null> {
actionName = ActionName.SetOnlineStatus;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload) {
// 可设置状态
// { status: 10, extStatus: 1027, batteryStatus: 0 }
// { status: 30, extStatus: 0, batteryStatus: 0 }
// { status: 50, extStatus: 0, batteryStatus: 0 }
// { status: 60, extStatus: 0, batteryStatus: 0 }
// { status: 70, extStatus: 0, batteryStatus: 0 }
const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus);
if (ret.result !== 0) {
throw new Error('设置在线状态失败');

View File

@@ -3,7 +3,6 @@ import { ActionName, BaseCheckResult } from '../types';
import * as fs from 'node:fs';
import { NTQQUserApi } from '@/core/apis/user';
import { checkFileReceived, uri2local } from '@/common/utils/file';
// import { log } from "../../../common/utils";
interface Payload {
file: string
@@ -24,7 +23,7 @@ export default class SetAvatar extends BaseAction<Payload, null> {
};
}
protected async _handle(payload: Payload): Promise<null> {
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
const { path, isLocal, errMsg, success } = (await uri2local(payload.file));
if (!success) {
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
}

View File

@@ -18,9 +18,7 @@ export default class TestApi01 extends BaseAction<Payload, any> {
actionName = ActionName.TestApi01;
// 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> {
return {
valid: true,
};
return { valid: true };
}
protected async _handle(payload: Payload): Promise<any> {
return await napCatCore.session.getMsgService().sendSsoCmdReqByContend(payload.cmd, payload.param);

View File

@@ -1,9 +1,7 @@
import BaseAction from '../BaseAction';
import { ActionName, BaseCheckResult } from '../types';
import { NTQQSystemApi, NTQQUserApi } from '@/core/apis';
import { ActionName } from '../types';
import { NTQQSystemApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import Ajv from 'ajv';
// 设置在线状态
const SchemaData = {
type: 'object',

View File

@@ -1,7 +1,7 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
import { NTQQGroupApi } from '@/core/apis';
const SchemaData = {
type: 'object',

View File

@@ -2,7 +2,7 @@ import BaseAction from '../BaseAction';
import fs from 'fs/promises';
import { ob11Config } from '@/onebot11/config';
import { UUIDConverter } from '@/common/utils/helper';
import { ActionName, BaseCheckResult } from '../types';
import { ActionName } from '../types';
import { ChatType, ElementType, FileElement, Peer, RawMessage, VideoElement } from '@/core/entities';
import { NTQQFileApi, NTQQFriendApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';

View File

@@ -24,12 +24,12 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetForwardMsg;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> {
const msgId = payload.message_id || payload.id;
if (!msgId) {
throw Error('message_id is required');
const msgIdMixOb11Id = payload.message_id || payload.id;
if (!msgIdMixOb11Id) {
throw Error('message_id or id is required');
}
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgId));
const rootMsgId = MessageUnique.getShortIdByMsgId(msgIdMixOb11Id);
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgIdMixOb11Id));
if (!rootMsg) {
throw Error('msg not found');
}
@@ -40,7 +40,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
const msgList = data.msgList;
const messages = await Promise.all(msgList.map(async msg => {
const resMsg = await OB11Constructor.message(msg);
resMsg.message_id = await MessageUnique.createMsg({ guildId:'',chatType:msg.chatType,peerUid:msg.peerUid },msg.msgId)!;
resMsg.message_id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)!;
return resMsg;
}));
messages.map(msg => {

View File

@@ -50,6 +50,7 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
}));
//转换消息
const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(msg)));
return { 'messages': ob11MsgList };

View File

@@ -6,7 +6,7 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: [ 'number' , 'string' ] },
group_id: { type: ['number', 'string'] },
type: { enum: [WebHonorType.ALL, WebHonorType.EMOTION, WebHonorType.LEGEND, WebHonorType.PERFROMER, WebHonorType.STORONGE_NEWBI, WebHonorType.TALKACTIVE] }
},
required: ['group_id']

View File

@@ -44,7 +44,6 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
} else {
const user_id = payload.user_id.toString();
const extendData = await NTQQUserApi.getUserDetailInfoByUinV2(user_id);
//console.log(extendData);
const uid = (await NTQQUserApi.getUidByUin(user_id))!;
if (!uid || uid.indexOf('*') != -1) {
const ret = {

View File

@@ -54,8 +54,6 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
if (PublishGroupBulletinResult.result != 0) {
throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`;
}
// 下面实现扬了
//await WebApi.setGroupNotice(payload.group_id, payload.content) ;
return null;
}
}

View File

@@ -4,7 +4,7 @@ import { ActionName } from '../types';
import { SendMsgElementConstructor } from '@/core/entities/constructor';
import { ChatType, SendFileElement } from '@/core/entities';
import fs from 'fs';
import { SendMsg, sendMsg } from '@/onebot11/action/msg/SendMsg';
import { sendMsg } from '@/onebot11/action/msg/SendMsg';
import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {

View File

@@ -1,10 +1,9 @@
import BaseAction from '../BaseAction';
import { getGroup } from '@/core/data';
import { ActionName } from '../types';
import { SendMsgElementConstructor } from '@/core/entities/constructor';
import { ChatType, Peer, SendFileElement } from '@/core/entities';
import fs from 'fs';
import { SendMsg, sendMsg } from '@/onebot11/action/msg/SendMsg';
import { sendMsg } from '@/onebot11/action/msg/SendMsg';
import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { NTQQFriendApi, NTQQUserApi } from '@/core';

View File

@@ -1,9 +1,5 @@
import { getGroup } from '@/core/data';
import { OB11Group } from '../../types';
import { OB11Constructor } from '../../constructor';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NTQQMsgApi } from '@/core/apis/msg';
import { GroupEssenceMsgRet, WebApi } from '@/core/apis/webapi';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';

View File

@@ -5,7 +5,6 @@ import { ActionName } from '../types';
import { NTQQGroupApi } from '@/core/apis';
import { Group } from '@/core/entities';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// no_cache get时传字符串
const SchemaData = {
type: 'object',
properties: {

View File

@@ -1,7 +1,7 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { NTQQGroupApi, NTQQMsgApi } from '@/core';
import { NTQQGroupApi } from '@/core';
import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = {
@@ -18,7 +18,7 @@ export default class SetEssenceMsg extends BaseAction<Payload, any> {
actionName = ActionName.SetEssenceMsg;
PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> {
const msg = await MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if (!msg) {
throw new Error('msg not found');
}

View File

@@ -9,7 +9,7 @@ const SchemaData = {
properties: {
flag: { type: 'string' },
approve: { type: ['string', 'boolean'] },
reason: { type: 'string', nullable: true, }
reason: { type: 'string', nullable: true }
},
required: ['flag'],
} as const satisfies JSONSchema;
@@ -24,7 +24,7 @@ export default class SetGroupAddRequest extends BaseAction<Payload, null> {
const approve = payload.approve?.toString() !== 'false';
await NTQQGroupApi.handleGroupRequest(flag,
approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject,
payload.reason
payload.reason || ''
);
return null;
}

View File

@@ -35,9 +35,7 @@ import SetGroupCard from './group/SetGroupCard';
import GetImage from './file/GetImage';
import GetRecord from './file/GetRecord';
import { GoCQHTTPMarkMsgAsRead, MarkAllMsgAsRead, MarkGroupMsgAsRead, MarkPrivateMsgAsRead } from './msg/MarkMsgAsRead';
import CleanCache from './system/CleanCache';
import GoCQHTTPUploadGroupFile from './go-cqhttp/UploadGroupFile';
import { GetConfigAction, SetConfigAction } from '@/onebot11/action/extends/Config';
import GetGroupAddRequest from '@/onebot11/action/extends/GetGroupAddRequest';
import SetQQAvatar from '@/onebot11/action/extends/SetQQAvatar';
import GoCQHTTPDownloadFile from './go-cqhttp/DownloadFile';

View File

@@ -28,7 +28,7 @@ class DeleteMsg extends BaseAction<Payload, void> {
protected async _handle(payload: Payload) {
const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id));
if (msg) {
let ret = NTEventDispatch.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']>
const ret = NTEventDispatch.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']>
(
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
@@ -39,9 +39,9 @@ class DeleteMsg extends BaseAction<Payload, void> {
}
return false;
}
).catch(e => new Promise<undefined>((resolve, reject) => { resolve(undefined) }));
).catch(e => new Promise<undefined>((resolve, reject) => { resolve(undefined); }));
await NTQQMsgApi.recallMsg(msg.Peer, [msg.MsgId]);
let data = await ret;
const data = await ret;
if (!data) {
throw new Error('Recall failed');
}

View File

@@ -30,7 +30,7 @@ class ForwardSingleMsg extends BaseAction<Payload, null> {
}
protected async _handle(payload: Payload): Promise<null> {
const msg = await MessageUnique.getMsgIdAndPeerByShortId(payload.message_id);
const msg = MessageUnique.getMsgIdAndPeerByShortId(payload.message_id);
if (!msg) {
throw new Error(`无法找到消息${payload.message_id}`);
}

View File

@@ -27,8 +27,8 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
if (!payload.message_id) {
throw Error('参数message_id不能为空');
}
const MsgShortId = await MessageUnique.getShortIdByMsgId(payload.message_id.toString());
const msgIdWithPeer = await MessageUnique.getMsgIdAndPeerByShortId(MsgShortId || parseInt(payload.message_id.toString()));
const MsgShortId = MessageUnique.getShortIdByMsgId(payload.message_id.toString());
const msgIdWithPeer = MessageUnique.getMsgIdAndPeerByShortId(MsgShortId || parseInt(payload.message_id.toString()));
if (!msgIdWithPeer) {
throw ('消息不存在');
}

View File

@@ -18,7 +18,7 @@ import { uri2local } from '@/common/utils/file';
import { ob11Config } from '@/onebot11/config';
import { RequestUtil } from '@/common/utils/request';
import { MessageUnique } from '@/common/utils/MessageUnique';
console.log(process.pid)
console.log(process.pid);
export type MessageContext = {
deleteAfterSentFiles: string[],
peer:Peer

View File

@@ -51,24 +51,24 @@ export async function handleForwardNode(destPeer: Peer, messageNodes: OB11Messag
} else {
// 自定义的消息
try {
let OB11Data = normalize(messageNode.data.content);
const OB11Data = normalize(messageNode.data.content);
//筛选node消息
let isNodeMsg = OB11Data.filter(e => e.type === OB11MessageDataType.node).length;//找到子转发消息
const isNodeMsg = OB11Data.filter(e => e.type === OB11MessageDataType.node).length;//找到子转发消息
if (isNodeMsg !== 0) {
if (isNodeMsg !== OB11Data.length) { logError('子消息中包含非node消息 跳过不合法部分'); continue; }
const nodeMsg = await handleForwardNode(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
if (nodeMsg) { nodeMsgIds.push(nodeMsg.msgId); MessageUnique.createMsg(selfPeer, nodeMsg.msgId) };
if (nodeMsg) { nodeMsgIds.push(nodeMsg.msgId); MessageUnique.createMsg(selfPeer, nodeMsg.msgId); }
//完成子卡片生成跳过后续
continue;
}
const { sendElements } = await createSendElements(OB11Data, destPeer);
//拆分消息
let MixElement = sendElements.filter(element => element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO);
let SingleElement = sendElements.filter(element => element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO).map(e => [e]);
let AllElement: SendMessageElement[][] = [MixElement, ...SingleElement].filter(e => e !== undefined && e.length !== 0);
const MixElement = sendElements.filter(element => element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO);
const SingleElement = sendElements.filter(element => element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO).map(e => [e]);
const AllElement: SendMessageElement[][] = [MixElement, ...SingleElement].filter(e => e !== undefined && e.length !== 0);
const MsgNodeList: Promise<RawMessage | undefined>[] = [];
for (const sendElementsSplitElement of AllElement) {
MsgNodeList.push(sendMsg(selfPeer, sendElementsSplitElement, [], true).catch(e => new Promise((resolve, reject) => { resolve(undefined) })));
MsgNodeList.push(sendMsg(selfPeer, sendElementsSplitElement, [], true).catch(e => new Promise((resolve, reject) => { resolve(undefined); })));
}
(await Promise.allSettled(MsgNodeList)).map((result) => {
if (result.status === 'fulfilled' && result.value) {
@@ -85,7 +85,7 @@ export async function handleForwardNode(destPeer: Peer, messageNodes: OB11Messag
let srcPeer: Peer | undefined = undefined;
let needSendSelf = false;
//检测是否处于同一个Peer 不在同一个peer则全部消息由自身发送
for (let msgId of nodeMsgIds) {
for (const msgId of nodeMsgIds) {
const nodeMsgPeer = MessageUnique.getPeerByMsgId(msgId);
if (!nodeMsgPeer) {
logError('转发消息失败,未找到消息', msgId);

View File

@@ -67,7 +67,7 @@ export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], de
}
const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, timeout);
try {
returnMsg!.id = await MessageUnique.createMsg({ chatType: peer.chatType, guildId: '', peerUid: peer.peerUid }, returnMsg!.msgId);
returnMsg!.id = MessageUnique.createMsg({ chatType: peer.chatType, guildId: '', peerUid: peer.peerUid }, returnMsg!.msgId);
} catch (e: any) {
logDebug('发送消息id获取失败', e);
returnMsg!.id = 0;
@@ -94,7 +94,8 @@ async function createContext(payload: OB11PostSendMsg, contextMode: ContextMode)
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy);
return {
chatType: isBuddy ? ChatType.friend : ChatType.temp,
peerUid: Uid!
peerUid: Uid!,
guildId: payload.group_id || ''//临时主动发起时需要传入群号
};
}
throw '请指定 group_id 或 user_id';

View File

@@ -11,5 +11,4 @@ class SendPrivateMsg extends SendMsg {
return super.check(payload);
}
}
export default SendPrivateMsg;

View File

@@ -14,7 +14,6 @@ const SchemaData = {
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class SetMsgEmojiLike extends BaseAction<Payload, any> {
actionName = ActionName.SetMsgEmojiLike;
PayloadSchema = SchemaData;

View File

@@ -4,7 +4,6 @@ import CanSendRecord from './CanSendRecord';
interface ReturnType {
yes: boolean
}
export default class CanSendImage extends CanSendRecord {
actionName = ActionName.CanSendImage;
}

View File

@@ -3,8 +3,6 @@ import { OB11User } from '../../types';
import { OB11Constructor } from '../../constructor';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { napCatCore } from '@/core';
class GetLoginInfo extends BaseAction<null, OB11User> {
actionName = ActionName.GetLoginInfo;

View File

@@ -15,8 +15,8 @@ export interface InvalidCheckResult {
export enum ActionName {
// 以下为扩展napcat扩展
SharePeer = 'ArkShareGroup',
ShareGroupEx = 'ArkSharePeer',
SharePeer = 'ArkSharePeer',
ShareGroupEx = 'ArkShareGroupEx',
RebootNormal = 'reboot_normal',//无快速登录重新启动
GetRobotUinRange = 'get_robot_uin_range',
SetOnlineStatus = 'set_online_status',

View File

@@ -6,8 +6,6 @@ import { ActionName } from '../types';
import { NTQQFriendApi } from '@/core';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
// no_cache get时传字符串
const SchemaData = {
type: 'object',

View File

@@ -13,7 +13,6 @@ const SchemaData = {
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export default class SendLike extends BaseAction<Payload, null> {
actionName = ActionName.SendLike;
PayloadSchema = SchemaData;

View File

@@ -1,10 +1,4 @@
import fs from 'node:fs';
import path from 'node:path';
import { selfInfo } from '@/core/data';
import { logDebug, logError } from '@/common/utils/log';
import { ConfigBase } from '@/common/utils/ConfigBase';
import { json } from 'stream/consumers';
export interface OB11Config {
http: {
enable: boolean;
@@ -36,7 +30,7 @@ export interface OB11Config {
Record: boolean,
RecordList: Array<string>
},
read(): OB11Config;
read(): OB11Config | null;
save(config: OB11Config): void;
}

View File

@@ -12,6 +12,7 @@ import {
import {
AtType,
ChatType,
ChatType2,
FaceIndex,
Friend,
FriendV2,
@@ -42,7 +43,7 @@ import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent';
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent';
import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent';
import { ob11Config } from '@/onebot11/config';
import { deleteGroup, getGroupMember, groupMembers, selfInfo, tempGroupCodeMap } from '@/core/data';
import { deleteGroup, getGroupMember, groupMembers, selfInfo } from '@/core/data';
import { NTQQFileApi, NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
import { OB11GroupMsgEmojiLikeEvent } from '@/onebot11/event/notice/OB11MsgEmojiLikeEvent';
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent';
@@ -96,11 +97,15 @@ export class OB11Constructor {
//const user = await NTQQUserApi.getUserDetailInfoByUin(msg.senderUin!);
//resMsg.sender.nickname = user.info.nick;
}
else if (msg.chatType == ChatType.temp) {
else if (msg.chatType as unknown as ChatType2 == ChatType2.KCHATTYPETEMPC2CFROMGROUP) {
resMsg.sub_type = 'group';
const tempGroupCode = tempGroupCodeMap[msg.peerUin];
if (tempGroupCode) {
resMsg.group_id = parseInt(tempGroupCode);
let ret = await NTQQMsgApi.getTempChatInfo(ChatType2.KCHATTYPETEMPC2CFROMGROUP, msg.senderUid);
if (ret.result === 0) {
resMsg.group_id = parseInt(ret.tmpChatInfo!.groupCode);
resMsg.sender.nickname = ret.tmpChatInfo!.fromNick;
} else {
resMsg.group_id = 284840486;//兜底数据
resMsg.sender.nickname = "临时会话";
}
}
for (const element of msg.elements) {
@@ -340,17 +345,17 @@ export class OB11Constructor {
msg.parentMsgIdList.push(msg.msgId);
//let parentMsgId = msg.parentMsgIdList[msg.parentMsgIdList.length - 2 < 0 ? 0 : msg.parentMsgIdList.length - 2];
//加入自身MsgId
let MultiMsgs = (await NTQQMsgApi.getMultiMsg(ParentMsgPeer, msg.parentMsgIdList[0], msg.msgId))?.msgList;
const MultiMsgs = (await NTQQMsgApi.getMultiMsg(ParentMsgPeer, msg.parentMsgIdList[0], msg.msgId))?.msgList;
//拉取下级消息
if (!MultiMsgs) continue;
//拉取失败则跳过
message_data['data']['content'] = [];
for (let MultiMsg of MultiMsgs) {
for (const MultiMsg of MultiMsgs) {
//对每条拉取的消息传递ParentMsgPeer修正Peer
MultiMsg.parentMsgPeer = ParentMsgPeer;
MultiMsg.parentMsgIdList = msg.parentMsgIdList;
MultiMsg.id = MessageUnique.createMsg(ParentMsgPeer, MultiMsg.msgId);//该ID仅用查看 无法调用
let msgList = await OB11Constructor.message(MultiMsg);
const msgList = await OB11Constructor.message(MultiMsg);
message_data['data']['content'].push(msgList);
//console.log("合并消息", msgList);
}
@@ -496,12 +501,10 @@ export class OB11Constructor {
const senderUin = emojiLikeData.gtip.qq.jp;
const msgSeq = emojiLikeData.gtip.url.msgseq;
const emojiId = emojiLikeData.gtip.face.id;
const replyMsgList = (await NTQQMsgApi.getMsgsBySeqAndCount({ chatType: ChatType.group, guildId: '', peerUid: msg.peerUid }, msgSeq, 1, true, true)).msgList;
if (replyMsgList.length < 1) {
return;
}
console.log('表情回应消息', msgSeq, " 结算ID", replyMsgList[0].msgId);
const replyMsg = replyMsgList[0];
return new OB11GroupMsgEmojiLikeEvent(parseInt(msg.peerUid), parseInt(senderUin), MessageUnique.getShortIdByMsgId(replyMsg?.msgId!)!, [{
emoji_id: emojiId,

View File

@@ -2,5 +2,5 @@ import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_admin';
sub_type: 'set' | 'unset' = "set"; // "set" | "unset"
sub_type: 'set' | 'unset' = 'set'; // "set" | "unset"
}

View File

@@ -3,7 +3,7 @@ import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
export class OB11InputStatusEvent extends OB11BaseNoticeEvent {
notice_type = 'notify';
sub_type = 'input_status';
status_text = "对方正在输入..."
status_text = '对方正在输入...';
eventType = 1;
user_id = 0;
constructor(user_id: number, eventType: number, status_text: string) {

View File

@@ -26,7 +26,7 @@ export async function logMessage(ob11Message: OB11Message) {
if (ob11Message.message_type === 'group') {
if (ob11Message.group_id == 284840486) {
group = await getGroup(ob11Message.group_id!);
prefix += `转发消息[外部来源] `;
prefix += '转发消息[外部来源] ';
} else {
group = await getGroup(ob11Message.group_id!);
prefix += `群[${group?.groupName}(${ob11Message.group_id})] `;

View File

@@ -19,7 +19,7 @@ import { OB11Config, ob11Config } from '@/onebot11/config';
import { httpHeart, ob11HTTPServer } from '@/onebot11/server/http';
import { ob11WebsocketServer } from '@/onebot11/server/ws/WebsocketServer';
import { ob11ReverseWebsockets } from '@/onebot11/server/ws/ReverseWebsocket';
import { getGroup, getGroupMember, groupMembers, selfInfo, tempGroupCodeMap } from '@/core/data';
import { getGroup, getGroupMember, groupMembers, selfInfo } from '@/core/data';
import { BuddyListener, GroupListener, NodeIKernelBuddyListener } from '@/core/listeners';
import { OB11FriendRequestEvent } from '@/onebot11/event/request/OB11FriendRequest';
import { NTQQGroupApi, NTQQUserApi, WebApi } from '@/core/apis';
@@ -104,10 +104,10 @@ export class NapCatOnebot11 {
toUin: string;
}
) => {
let uin = await NTQQUserApi.getUinByUid(data.fromUin);
const uin = await NTQQUserApi.getUinByUid(data.fromUin);
logNotice(`[输入状态] ${uin} ${data.statusText}`);
postOB11Event(new OB11InputStatusEvent(parseInt(uin), data.eventType, data.statusText));
}
};
msgListener.onRecvSysMsg = async (protobufData: number[]) => {
// function buf2hex(buffer: Buffer) {
// return [...new Uint8Array(buffer)]
@@ -222,12 +222,13 @@ export class NapCatOnebot11 {
selfInfo.online = false;
};
msgListener.onTempChatInfoUpdate = (tempChatInfo: TempOnRecvParams) => {
if (tempChatInfo.sessionType == 1 && tempChatInfo.chatType == ChatType.temp) {
tempGroupCodeMap[tempChatInfo.peerUid] = tempChatInfo.groupCode;
}
// if (tempChatInfo.sessionType == 1 && tempChatInfo.chatType == ChatType.temp) {
// tempGroupCodeMap[tempChatInfo.peerUid] = tempChatInfo.groupCode;
// }
// 临时会话更新 tempGroupCodeMap uid -> source/GroupCode
};
msgListener.onRecvMsg = async (msg) => {
//console.log('ob11 onRecvMsg', JSON.stringify(msg, null, 2));
// logDebug('收到消息', msg);
for (const m of msg) {
@@ -253,7 +254,6 @@ export class NapCatOnebot11 {
// console.log(ret);
new Promise((resolve) => {
m.id = MessageUnique.createMsg({ chatType: m.chatType, peerUid: m.peerUid, guildId: '' }, m.msgId);
console.log("消息接收 ", "MsgID", m.msgId, " ID", m.id, " MsgSeq", m.msgSeq, " Raw", m?.elements[0]?.textElement?.content);
this.postReceiveMsg([m]).then().catch(logError);
}).then();
}
@@ -266,7 +266,6 @@ export class NapCatOnebot11 {
//完成后再post
OB11Constructor.message(msg).then((_msg) => {
_msg.target_id = parseInt(msg.peerUin);
console.log("自身消息接收 ", "MsgID", msg.msgId, " MsgSeq", msg.msgSeq, " Raw", msg?.elements[0]?.textElement?.content);
if (ob11Config.reportSelfMessage) {
msg.id = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid, guildId: '' }, msg.msgId);
this.postReceiveMsg([msg]).then().catch(logError);

View File

@@ -1 +1 @@
export const version = '1.8.3';
export const version = '1.8.4';

View File

@@ -29,7 +29,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
undefined,
SettingButton('V1.8.3', 'napcat-update-button', 'secondary')
SettingButton('V1.8.4', 'napcat-update-button', 'secondary')
),
]),
SettingList([

View File

@@ -163,7 +163,7 @@ async function onSettingWindowCreated(view) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
void 0,
SettingButton("V1.8.3", "napcat-update-button", "secondary")
SettingButton("V1.8.4", "napcat-update-button", "secondary")
)
]),
SettingList([