mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c3d737219 | ||
![]() |
a1f38fed7a | ||
![]() |
c36bb77286 | ||
![]() |
1a1acdc3c9 | ||
![]() |
ef8e60c405 | ||
![]() |
31c1cc47bf | ||
![]() |
351fed7359 | ||
![]() |
f49e7cbe57 | ||
![]() |
7da8ea5e99 | ||
![]() |
8fa6a12a7c |
@@ -1,21 +0,0 @@
|
||||
# v1.8.0
|
||||
|
||||
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
|
||||
|
||||
## 启动的方式
|
||||
Way03/Way05
|
||||
|
||||
## 新增与调整
|
||||
1. 消息ID映射到UINT32空间
|
||||
2. 回复ID验证与修复
|
||||
3. 新API /fetch_emoji_like
|
||||
|
||||
```json5
|
||||
{
|
||||
"message_id": 1557274996,//消息ID
|
||||
"emojiType": "1",//可以从event事件获取 一般为1或者2
|
||||
"emojiId": "76"//可以从event事件获取 一个表情对应一个ID
|
||||
}
|
||||
```
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/CHANGELOG.v1.8.1.md
Normal file
13
docs/changelogs/CHANGELOG.v1.8.1.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# v1.8.1
|
||||
|
||||
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
|
||||
|
||||
## 启动的方式
|
||||
Way03/Way05
|
||||
|
||||
## 新增与调整
|
||||
1. 多层转发消息解析
|
||||
2. 撤回消息附带反馈
|
||||
3. 文件上传兼容性提升
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"scripts": {
|
||||
"watch:dev": "vite --mode development",
|
||||
"watch:prod": "vite --mode production",
|
||||
|
@@ -6,15 +6,15 @@ import AppidTable from '@/core/external/appid.json';
|
||||
import { log } from './log';
|
||||
|
||||
//基础目录获取
|
||||
export let QQMainPath = process.execPath;
|
||||
export let QQPackageInfoPath: string = path.join(path.dirname(QQMainPath), 'resources', 'app', 'package.json');
|
||||
export let QQVersionConfigPath: string | undefined = getQQVersionConfigPath(QQMainPath);
|
||||
export const QQMainPath = process.execPath;
|
||||
export const QQPackageInfoPath: string = path.join(path.dirname(QQMainPath), 'resources', 'app', 'package.json');
|
||||
export const QQVersionConfigPath: string | undefined = getQQVersionConfigPath(QQMainPath);
|
||||
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
export let isQuickUpdate: boolean = !!QQVersionConfigPath;
|
||||
export let QQVersionConfig: QQVersionConfigType = isQuickUpdate ? JSON.parse(fs.readFileSync(QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
||||
export let QQPackageInfo: QQPackageInfoType = JSON.parse(fs.readFileSync(QQPackageInfoPath).toString());
|
||||
export let { appid: QQVersionAppid, qua: QQVersionQua } = getAppidV2();
|
||||
export const isQuickUpdate: boolean = !!QQVersionConfigPath;
|
||||
export const QQVersionConfig: QQVersionConfigType = isQuickUpdate ? JSON.parse(fs.readFileSync(QQVersionConfigPath!).toString()) : getDefaultQQVersionConfigInfo();
|
||||
export const QQPackageInfo: QQPackageInfoType = JSON.parse(fs.readFileSync(QQPackageInfoPath).toString());
|
||||
export const { appid: QQVersionAppid, qua: QQVersionQua } = getAppidV2();
|
||||
|
||||
//基础函数
|
||||
export function getQQBuildStr() {
|
||||
@@ -31,17 +31,18 @@ export function getQUAInternal() {
|
||||
return systemPlatform === 'linux' ? `V1_LNX_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B` : `V1_WIN_NQ_${getFullQQVesion()}_${getQQBuildStr()}_GW_B`;
|
||||
}
|
||||
export function getAppidV2(): { appid: string, qua: string } {
|
||||
let appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||
try {
|
||||
let data = appidTbale[getFullQQVesion()];
|
||||
const data = appidTbale[getFullQQVesion()];
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
log('[QQ版本兼容性检测] 版本兼容性不佳,可能会导致一些功能无法正常使用', e);
|
||||
log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
}
|
||||
// 以下是兜底措施
|
||||
log(`[QQ版本兼容性检测] ${getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`);
|
||||
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: getQUAInternal() };
|
||||
}
|
||||
// platform_type: 3,
|
||||
|
@@ -181,7 +181,7 @@ type Uri2LocalRes = {
|
||||
isLocal: boolean
|
||||
}
|
||||
|
||||
export async function uri2local(uri: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||
export async function uri2local(UriOrPath: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||
const res = {
|
||||
success: false,
|
||||
errMsg: '',
|
||||
@@ -190,26 +190,29 @@ export async function uri2local(uri: string, fileName: string | null = null): Pr
|
||||
path: '',
|
||||
isLocal: false
|
||||
};
|
||||
if (!fileName) {
|
||||
fileName = randomUUID();
|
||||
}
|
||||
let filePath = path.join(getTempDir(), fileName);
|
||||
if (!fileName) fileName = randomUUID();
|
||||
let filePath = path.join(getTempDir(), fileName);//临时目录
|
||||
let url = null;
|
||||
//区分path和uri
|
||||
try {
|
||||
url = new URL(uri);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `uri ${uri} 解析失败,` + e.toString() + ` 可能${uri}不存在`;
|
||||
if (fs.existsSync(UriOrPath)) url = new URL('file://' + UriOrPath);
|
||||
} catch (error: any) { }
|
||||
try {
|
||||
url = new URL(UriOrPath);
|
||||
} catch (error: any) { }
|
||||
|
||||
//验证url
|
||||
if (!url) {
|
||||
res.errMsg = `UriOrPath ${UriOrPath} 解析失败,可能${UriOrPath}不存在`;
|
||||
return res;
|
||||
}
|
||||
|
||||
// log("uri protocol", url.protocol, uri);
|
||||
if (url.protocol == 'base64:') {
|
||||
// base64转成文件
|
||||
const base64Data = uri.split('base64://')[1];
|
||||
const base64Data = UriOrPath.split('base64://')[1];
|
||||
try {
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
|
||||
} catch (e: any) {
|
||||
res.errMsg = 'base64文件下载失败,' + e.toString();
|
||||
return res;
|
||||
@@ -218,7 +221,7 @@ export async function uri2local(uri: string, fileName: string | null = null): Pr
|
||||
// 下载文件
|
||||
let buffer: Buffer | null = null;
|
||||
try {
|
||||
buffer = await httpDownload(uri);
|
||||
buffer = await httpDownload(UriOrPath);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `${url}下载失败,` + e.toString();
|
||||
return res;
|
||||
@@ -252,6 +255,7 @@ export async function uri2local(uri: string, fileName: string | null = null): Pr
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 26702执行forword file文件操作 不应该在这里乱来
|
||||
// const cache = await dbUtil.getFileCacheByName(uri);
|
||||
// if (cache) {
|
||||
// filePath = cache.path;
|
||||
@@ -259,7 +263,6 @@ export async function uri2local(uri: string, fileName: string | null = null): Pr
|
||||
// filePath = uri;
|
||||
// }
|
||||
}
|
||||
|
||||
res.isLocal = true;
|
||||
}
|
||||
// else{
|
||||
|
@@ -360,12 +360,12 @@ export async function promisePipeline(promises: Promise<any>[], callback: (resul
|
||||
callbackCalled = callback(result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in promise pipeline:", error);
|
||||
console.error('Error in promise pipeline:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getQQVersionConfigPath(exePath: string = ""): string | undefined {
|
||||
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
|
||||
let configVersionInfoPath;
|
||||
if (os.platform() !== 'linux') {
|
||||
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
|
||||
|
@@ -67,6 +67,9 @@ setTimeout(() => {
|
||||
// }, 25000)
|
||||
|
||||
export class NTQQMsgApi {
|
||||
static async FetchLongMsg(peer: Peer, msgId: string) {
|
||||
return napCatCore.session.getMsgService().fetchLongMsg(peer, msgId);
|
||||
}
|
||||
static async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
||||
//console.log(peer, msgSeq, emojiId, emojiType, count);
|
||||
return napCatCore.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, "", false, 20)
|
||||
@@ -100,7 +103,7 @@ export class NTQQMsgApi {
|
||||
filterMsgFromTime: '0',
|
||||
isReverseOrder: false,
|
||||
isIncludeCurrent: true,
|
||||
pageLimit: 1,
|
||||
pageLimit: count,
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
@@ -731,10 +731,12 @@ export interface MultiForwardMsgElement {
|
||||
}
|
||||
|
||||
export interface RawMessage {
|
||||
parentMsgPeer: Peer;
|
||||
parentMsgIdList:string[];
|
||||
id?: number;//扩展字段 用于处理OB11 ID
|
||||
guildId: string;
|
||||
msgRandom: string;
|
||||
// int32, 自己维护的消息id
|
||||
id?: number;
|
||||
|
||||
|
||||
msgId: string;
|
||||
|
||||
|
8
src/core/src/external/appid.json
vendored
8
src/core/src/external/appid.json
vendored
@@ -11,6 +11,10 @@
|
||||
"appid": 537237950,
|
||||
"qua": "V1_LNX_NQ_3.2.12_26702_GW_B"
|
||||
},
|
||||
"3.2.12-26740": {
|
||||
"appid": 537237950,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26740_GW_B"
|
||||
},
|
||||
"9.9.11-24815": {
|
||||
"appid": 537226656,
|
||||
"qua": "V1_WIN_NQ_9.9.11_24815_GW_B"
|
||||
@@ -38,5 +42,9 @@
|
||||
"9.9.15-26702": {
|
||||
"appid": 537237765,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26702_GW_B"
|
||||
},
|
||||
"9.9.15-26740": {
|
||||
"appid": 537237765,
|
||||
"qua": "V1_WIN_NQ_9.9.15_26702_GW_B"
|
||||
}
|
||||
}
|
@@ -5,28 +5,28 @@ import { ActionName } from '../types';
|
||||
import { NTQQMsgApi } from '@/core/apis';
|
||||
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user_id: { type: 'string' },
|
||||
group_id: { type: 'string' },
|
||||
emojiId: { type: 'string' },
|
||||
emojiType: { type: 'string' },
|
||||
message_id: { type: ['string', 'number'] },
|
||||
count: { type: 'number' }
|
||||
},
|
||||
required: ['emojiId', 'emojiType', 'message_id']
|
||||
type: 'object',
|
||||
properties: {
|
||||
user_id: { type: 'string' },
|
||||
group_id: { type: 'string' },
|
||||
emojiId: { type: 'string' },
|
||||
emojiType: { type: 'string' },
|
||||
message_id: { type: ['string', 'number'] },
|
||||
count: { type: 'number' }
|
||||
},
|
||||
required: ['emojiId', 'emojiType', 'message_id']
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class FetchEmojioLike extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.FetchEmojioLike;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
let msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||
if(!msgIdPeer) throw new Error('消息不存在');
|
||||
let 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);
|
||||
return ret;
|
||||
}
|
||||
actionName = ActionName.FetchEmojioLike;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||
if(!msgIdPeer) throw new Error('消息不存在');
|
||||
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
|
||||
const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,8 @@ export class OCRImage extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.OCRImage;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
const { path, isLocal, errMsg } = (await uri2local(payload.image));
|
||||
if (errMsg) {
|
||||
const { path, isLocal, errMsg,success } = (await uri2local(payload.image));
|
||||
if (!success) {
|
||||
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
|
@@ -26,8 +26,8 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
|
||||
};
|
||||
}
|
||||
protected async _handle(payload: Payload): Promise<any> {
|
||||
const { path, isLocal, errMsg } = (await uri2local(payload.file));
|
||||
if (errMsg) {
|
||||
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
|
@@ -24,8 +24,8 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
||||
};
|
||||
}
|
||||
protected async _handle(payload: Payload): Promise<null> {
|
||||
const { path, isLocal, errMsg } = (await uri2local(payload.file));
|
||||
if (errMsg) {
|
||||
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
}
|
||||
if (path) {
|
||||
|
@@ -37,7 +37,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
||||
peerUid: group.groupCode
|
||||
};
|
||||
let msgList: RawMessage[];
|
||||
if (!payload.message_seq) {
|
||||
if (!payload.message_seq || payload.message_seq === 0) {
|
||||
msgList = (await NTQQMsgApi.getLastestMsgByUids(peer, count)).msgList;
|
||||
} else {
|
||||
const startMsgId = (await MessageUnique.getMsgIdAndPeerByShortId(targetMsgShortId ?? (payload.message_seq ?? 0)))?.MsgId || '0';
|
||||
|
@@ -7,7 +7,7 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: [ 'number' , 'string' ] },
|
||||
group_id: { type: ['number', 'string'] },
|
||||
content: { type: 'string' },
|
||||
image: { type: 'string' },
|
||||
pinned: { type: 'number' },
|
||||
@@ -24,8 +24,8 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
let UploadImage: { id: string, width: number, height: number } | undefined = undefined;
|
||||
if (payload.image) {
|
||||
//公告图逻辑
|
||||
const { errMsg, path, isLocal } = (await uri2local(payload.image));
|
||||
if (errMsg) {
|
||||
const { errMsg, path, isLocal, success } = (await uri2local(payload.image));
|
||||
if (!success) {
|
||||
throw `群公告${payload.image}设置失败,image字段可能格式不正确`;
|
||||
}
|
||||
if (!path) {
|
||||
|
@@ -34,7 +34,7 @@ export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> {
|
||||
file = `file://${file}`;
|
||||
}
|
||||
const downloadResult = await uri2local(file);
|
||||
if (downloadResult.errMsg) {
|
||||
if (!downloadResult.success) {
|
||||
throw new Error(downloadResult.errMsg);
|
||||
}
|
||||
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(downloadResult.path, payload.name, payload.folder_id);
|
||||
|
@@ -41,7 +41,7 @@ export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null>
|
||||
file = `file://${file}`;
|
||||
}
|
||||
const downloadResult = await uri2local(file);
|
||||
if (downloadResult.errMsg) {
|
||||
if (!downloadResult.success) {
|
||||
throw new Error(downloadResult.errMsg);
|
||||
}
|
||||
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(downloadResult.path, payload.name);
|
||||
|
@@ -19,7 +19,7 @@ class GetGroupList extends BaseAction<Payload, OB11Group[]> {
|
||||
actionName = ActionName.GetGroupList;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
let groupList: Group[] = await NTQQGroupApi.getGroups(payload?.no_cache === true || payload.no_cache === 'true');
|
||||
const groupList: Group[] = await NTQQGroupApi.getGroups(payload?.no_cache === true || payload.no_cache === 'true');
|
||||
return OB11Constructor.groups(groupList);
|
||||
}
|
||||
}
|
||||
|
@@ -26,11 +26,11 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
const isNocache = payload.no_cache == true || payload.no_cache === 'true';
|
||||
let uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
||||
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
||||
if (!uid) {
|
||||
throw (`Uin2Uid Error ${payload.user_id}不存在`);
|
||||
}
|
||||
let member = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache);
|
||||
const member = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache);
|
||||
if (!member) {
|
||||
throw (`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
const date = Math.round(Date.now() / 1000);
|
||||
const retMember = OB11Constructor.groupMember(payload.group_id.toString(), member);
|
||||
if (!requireMinNTQQBuild('26702')) {
|
||||
let SelfInfoInGroup = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), selfInfo.uid, isNocache);
|
||||
const SelfInfoInGroup = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), selfInfo.uid, isNocache);
|
||||
let isPrivilege = false;
|
||||
if (SelfInfoInGroup) {
|
||||
isPrivilege = SelfInfoInGroup.role === 3 || SelfInfoInGroup.role === 4;
|
||||
|
@@ -28,7 +28,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
if (requireMinNTQQBuild('26702')) {
|
||||
let V2Data = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), payload.user_id.toString(), payload.no_cache == true || payload.no_cache === 'true');
|
||||
const V2Data = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), payload.user_id.toString(), payload.no_cache == true || payload.no_cache === 'true');
|
||||
if (V2Data) {
|
||||
return OB11Constructor.groupMember(payload.group_id.toString(), V2Data);
|
||||
} else {
|
||||
|
@@ -30,7 +30,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
||||
if (!group) {
|
||||
throw (`群${payload.group_id}不存在`);
|
||||
}
|
||||
let groupMembers = await NTQQGroupApi.getGroupMembers(payload.group_id.toString());
|
||||
const groupMembers = await NTQQGroupApi.getGroupMembers(payload.group_id.toString());
|
||||
let _groupMembers = Array.from(groupMembers.values())
|
||||
.map(item => { return OB11Constructor.groupMember(group.groupCode, item); });
|
||||
|
||||
|
@@ -3,12 +3,15 @@ import { ActionName } from '../types';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||
import { sleep } from '@/common/utils/helper';
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||
import { NodeIKernelMsgListener } from '@/core';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
message_id: {
|
||||
oneOf:[
|
||||
oneOf: [
|
||||
{ type: 'number' },
|
||||
{ type: 'string' }
|
||||
]
|
||||
@@ -23,9 +26,27 @@ class DeleteMsg extends BaseAction<Payload, void> {
|
||||
actionName = ActionName.DeleteMsg;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
const msg = await MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id));
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id));
|
||||
if (msg) {
|
||||
let ret = NTEventDispatch.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']>
|
||||
(
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
5000,
|
||||
(msgs) => {
|
||||
if (msgs.find(m => m.msgId === msg.MsgId && m.recallTime !== '0')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
).catch(e => new Promise<undefined>((resolve, reject) => { resolve(undefined) }));
|
||||
await NTQQMsgApi.recallMsg(msg.Peer, [msg.MsgId]);
|
||||
let data = await ret;
|
||||
if (!data) {
|
||||
throw new Error('Recall failed');
|
||||
}
|
||||
//await sleep(100);
|
||||
//await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,9 +27,9 @@ async function handleOb11FileLikeMessage(
|
||||
{ deleteAfterSentFiles }: MessageContext
|
||||
) {
|
||||
//有的奇怪的框架将url作为参数 而不是file 此时优先url
|
||||
const { path, isLocal, fileName, errMsg } = (await uri2local(inputdata?.url || inputdata.file));
|
||||
const { path, isLocal, fileName, errMsg,success } = (await uri2local(inputdata?.url || inputdata.file));
|
||||
|
||||
if (errMsg) {
|
||||
if (!success) {
|
||||
logError('文件下载失败', errMsg);
|
||||
throw Error('文件下载失败' + errMsg);
|
||||
}
|
||||
|
@@ -103,5 +103,5 @@ export enum ActionName {
|
||||
FetchCustomFace = 'fetch_custom_face',
|
||||
GOCQHTTP_UploadPrivateFile = 'upload_private_file',
|
||||
TestApi01 = 'test_api_01',
|
||||
FetchEmojioLike = "fetch_emoji_like"
|
||||
FetchEmojioLike = 'fetch_emoji_like'
|
||||
}
|
||||
|
@@ -18,12 +18,12 @@ export default class GetRecentContact extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GetRecentContact;
|
||||
PayloadSchema = SchemaData;
|
||||
protected async _handle(payload: Payload) {
|
||||
let ret = await NTQQUserApi.getRecentContactListSnapShot(parseInt((payload.count || 10).toString()));
|
||||
let data = await Promise.all(ret.info.changedList.map(async (t) => {
|
||||
let FastMsg = await NTQQMsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
|
||||
const ret = await NTQQUserApi.getRecentContactListSnapShot(parseInt((payload.count || 10).toString()));
|
||||
const data = await Promise.all(ret.info.changedList.map(async (t) => {
|
||||
const FastMsg = await NTQQMsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
|
||||
if (FastMsg.msgList.length > 0) {
|
||||
//扩展ret.info.changedList
|
||||
let lastestMsg = await OB11Constructor.message(FastMsg.msgList[0]);
|
||||
const lastestMsg = await OB11Constructor.message(FastMsg.msgList[0]);
|
||||
return {
|
||||
lastestMsg: lastestMsg,
|
||||
peerUin: t.peerUin,
|
||||
|
@@ -65,7 +65,7 @@ export class OB11Constructor {
|
||||
real_id: msg.id!,
|
||||
message_type: msg.chatType == ChatType.group ? 'group' : 'private',
|
||||
sender: {
|
||||
user_id: parseInt(msg.senderUin!),
|
||||
user_id: parseInt(msg.senderUin || '0'),
|
||||
nickname: msg.sendNickName,
|
||||
card: msg.sendMemberName || '',
|
||||
},
|
||||
@@ -165,8 +165,10 @@ export class OB11Constructor {
|
||||
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
|
||||
}
|
||||
|
||||
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||
if (msg.peerUin == '284840486') {
|
||||
//合并消息内侧 消息具体定位不到
|
||||
}
|
||||
if ((!replyMsg || records.msgRandom !== replyMsg.msgRandom) && msg.peerUin !== '284840486') {
|
||||
throw new Error('回复消息消息验证失败');
|
||||
}
|
||||
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgId)?.toString();
|
||||
@@ -221,6 +223,9 @@ export class OB11Constructor {
|
||||
const videoElement: VideoElement = element.videoElement;
|
||||
//读取视频链接并兜底
|
||||
let videoUrl;//Array
|
||||
if (msg.peerUin = '284840486') {
|
||||
//合并消息内部 应该进行特殊处理
|
||||
}
|
||||
try {
|
||||
videoUrl = await NTQQFileApi.getVideoUrl({
|
||||
chatType: msg.chatType,
|
||||
@@ -327,6 +332,27 @@ export class OB11Constructor {
|
||||
else if (element.multiForwardMsgElement) {
|
||||
message_data['type'] = OB11MessageDataType.forward;
|
||||
message_data['data']['id'] = msg.msgId;
|
||||
const ParentMsgPeer = msg.parentMsgPeer ?? { chatType: msg.chatType, guildId: '', peerUid: msg.peerUid };
|
||||
//判断是否在合并消息内
|
||||
msg.parentMsgIdList = msg.parentMsgIdList ?? [];
|
||||
//首次列表不存在则开始创建
|
||||
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;
|
||||
//拉取下级消息
|
||||
if (!MultiMsgs) continue;
|
||||
//拉取失败则跳过
|
||||
message_data['data']['content'] = [];
|
||||
for (let 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);
|
||||
message_data['data']['content'].push(msgList);
|
||||
//console.log("合并消息", msgList);
|
||||
}
|
||||
}
|
||||
if ((message_data.type as string) !== 'unknown' && message_data.data) {
|
||||
const cqCode = encodeCQCode(message_data);
|
||||
|
@@ -2,7 +2,7 @@ import { OB11Message } from '@/onebot11/types';
|
||||
import { log } from '@/common/utils/log';
|
||||
import { getGroup, getGroupMember, selfInfo } from '@/core/data';
|
||||
import exp from 'constants';
|
||||
import { Group } from '@/core';
|
||||
import { Group, NTQQMsgApi } from '@/core';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const spSegColor = chalk.blue;// for special segment
|
||||
@@ -24,8 +24,13 @@ export async function logMessage(ob11Message: OB11Message) {
|
||||
}
|
||||
}
|
||||
if (ob11Message.message_type === 'group') {
|
||||
group = await getGroup(ob11Message.group_id!);
|
||||
prefix += `群[${group?.groupName}(${ob11Message.group_id})] `;
|
||||
if (ob11Message.group_id == 284840486) {
|
||||
group = await getGroup(ob11Message.group_id!);
|
||||
prefix += `转发消息[外部来源] `;
|
||||
} else {
|
||||
group = await getGroup(ob11Message.group_id!);
|
||||
prefix += `群[${group?.groupName}(${ob11Message.group_id})] `;
|
||||
}
|
||||
}
|
||||
let msgChain = '';
|
||||
if (Array.isArray(ob11Message.message)) {
|
||||
@@ -66,6 +71,13 @@ export async function logMessage(ob11Message: OB11Message) {
|
||||
else if (segment.type === 'video') {
|
||||
msgParts.push(spSegColor(`[视频|${segment.data.url}]`));
|
||||
}
|
||||
else if (segment.type === 'forward') {
|
||||
msgParts.push(spSegColor(`[转发|${segment.data.id}|消息开始]`));
|
||||
segment.data.content.forEach((msg) => {
|
||||
logMessage(msg);
|
||||
});
|
||||
msgParts.push(spSegColor(`[转发|${segment.data.id}|消息结束]`));
|
||||
}
|
||||
else {
|
||||
msgParts.push(spSegColor(`[未实现|${JSON.stringify(segment)}]`));
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ class OB11HTTPServer extends HttpServerBase {
|
||||
name = 'OneBot V11 server';
|
||||
|
||||
handleFailed(res: Response, payload: any, e: Error) {
|
||||
res.send(OB11Response.error(e?.stack?.toString() || e.message || "Error Handle", 200));
|
||||
res.send(OB11Response.error(e?.stack?.toString() || e.message || 'Error Handle', 200));
|
||||
}
|
||||
|
||||
protected listen(port: number, host: string) {
|
||||
|
@@ -181,7 +181,8 @@ export interface OB11MessageMarkdown {
|
||||
export interface OB11MessageForward {
|
||||
type: OB11MessageDataType.forward
|
||||
data: {
|
||||
id: string
|
||||
id: string,
|
||||
content: OB11Message[]
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
export const version = '1.8.0';
|
||||
export const version = '1.8.1';
|
||||
|
@@ -29,7 +29,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V1.8.0', 'napcat-update-button', 'secondary')
|
||||
SettingButton('V1.8.1', 'napcat-update-button', 'secondary')
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -163,7 +163,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V1.8.0", "napcat-update-button", "secondary")
|
||||
SettingButton("V1.8.1", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
Reference in New Issue
Block a user