Merge branch 'main' into event-via-emitter

This commit is contained in:
Wesley F. Young 2024-08-29 00:54:23 +08:00
commit b6a4c5e755
12 changed files with 230 additions and 130 deletions

View File

@ -4,7 +4,7 @@
"name": "NapCatQQ", "name": "NapCatQQ",
"slug": "NapCat.Framework", "slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现", "description": "高性能的 OneBot 11 协议实现",
"version": "2.2.21", "version": "2.2.22",
"icon": "./logo.png", "icon": "./logo.png",
"authors": [ "authors": [
{ {

View File

@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "2.2.21", "version": "2.2.22",
"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",

View File

@ -1,7 +1,7 @@
import path from 'node:path'; import path from 'node:path';
import fs from 'fs'; import fs from 'fs';
import os from 'node:os'; import os from 'node:os';
import { QQLevel } from '@/core'; import { Peer, QQLevel } from '@/core';
export async function solveProblem<T extends (...arg: any[]) => any>(func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> { export async function solveProblem<T extends (...arg: any[]) => any>(func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> {
return new Promise<ReturnType<T> | undefined>((resolve) => { return new Promise<ReturnType<T> | undefined>((resolve) => {
@ -23,29 +23,48 @@ export async function solveAsyncProblem<T extends (...args: any[]) => Promise<an
}); });
}); });
} }
export class FileNapCatOneBotUUID {
//下面这个类是用于将uid+msgid合并的类 static encodeModelId(peer: Peer, modelId: string): string {
export class UUIDConverter { return `NapCatOneBot-ModeldFile-${peer.chatType}-${peer.peerUid}-${modelId}`;
static encode(highStr: string, lowStr: string): string {
const high = BigInt(highStr);
const low = BigInt(lowStr);
const highHex = high.toString(16).padStart(16, '0');
const lowHex = low.toString(16).padStart(16, '0');
const combinedHex = highHex + lowHex;
return `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring(
12,
16,
)}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`;
} }
static decodeModelId(uuid: string): undefined | {
static decode(uuid: string): { high: string; low: string } { peer: Peer,
const hex = uuid.replace(/-/g, ''); modelId: string
const high = BigInt('0x' + hex.substring(0, 16)); } {
const low = BigInt('0x' + hex.substring(16)); if (!uuid.startsWith('NapCatOneBot-ModeldFile-')) return undefined;
return { high: high.toString(), low: low.toString() }; const data = uuid.split('-');
if (data.length !== 5) return undefined;
const [, , chatType, peerUid, modelId] = data;
return {
peer: {
chatType: chatType as any,
peerUid: peerUid
},
modelId,
};
}
static encode(peer: Peer, msgId: string, elementId: string): string {
return `NapCatOneBot-MsgFile-${peer.chatType}-${peer.peerUid}-${msgId}-${elementId}`;
}
static decode(uuid: string): undefined | {
peer: Peer,
msgId: string,
elementId: string
} {
if (!uuid.startsWith('NapCatOneBot-File-')) return undefined;
const data = uuid.split('-');
if (data.length !== 6) return undefined;
const [, , chatType, peerUid, msgId, elementId] = data;
return {
peer: {
chatType: chatType as any,
peerUid: peerUid
},
msgId,
elementId,
};
} }
} }
export function sleep(ms: number): Promise<void> { export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }

View File

@ -1 +1 @@
export const napCatVersion = '2.2.21'; export const napCatVersion = '2.2.22';

View File

@ -302,7 +302,18 @@ export class NTQQFileApi {
async downloadMediaByUuid() { async downloadMediaByUuid() {
//napCatCore.session.getRichMediaService().downloadFileForFileUuid(); //napCatCore.session.getRichMediaService().downloadFileForFileUuid();
} }
async downloadFileForModelId(peer: Peer, modelId: string, timeout = 1000 * 60 * 2) {
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelRichMediaService/downloadFileForModelId',
'NodeIKernelMsgListener/onRichMediaDownloadComplete',
[peer, [modelId]],
() => true,
(arg) => arg?.commonFileInfo?.fileModelId === modelId,
1,
timeout,
);
return fileTransNotifyInfo.filePath;
}
async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) { async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
//logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force); //logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
// 用于下载收到的消息中的图片等 // 用于下载收到的消息中的图片等

View File

@ -1,5 +1,25 @@
import { ChatType, RawMessage } from '@/core/entities'; import { ChatType, RawMessage } from '@/core/entities';
export interface CommonFileInfo {
bizType: null;
chatType: number;
elemId: string;
favId: null;
fileModelId: string;
fileName: string;
fileSize: string;
md5: string;
md510m: string;
msgId: string;
msgTime: string;
parent: null;
peerUid: string;
picThumbPath: null;
sha: string;
sha3: string;
subId: string;
uuid: string;
[property: string]: any;
}
export interface OnRichMediaDownloadCompleteParams { export interface OnRichMediaDownloadCompleteParams {
fileModelId: string, fileModelId: string,
msgElementId: string, msgElementId: string,
@ -15,7 +35,7 @@ export interface OnRichMediaDownloadCompleteParams {
totalSize: string, totalSize: string,
trasferStatus: number, trasferStatus: number,
step: number, step: number,
commonFileInfo: unknown | null, commonFileInfo?: CommonFileInfo,
fileSrvErrCode: string, fileSrvErrCode: string,
clientMsg: string, clientMsg: string,
businessId: number, businessId: number,

View File

@ -155,7 +155,7 @@ export interface NodeIKernelRichMediaService {
}): unknown; }): unknown;
//arg3为“” //arg3为“”
downloadFileForModelId(peer: Peer, ModelId: string[], arg3: string): unknown; downloadFileForModelId(peer: Peer, ModelId: string[]): Promise<unknown>;
//第三个参数 Array<Type> //第三个参数 Array<Type>
// this.fileId = ""; // this.fileId = "";

View File

@ -1,8 +1,8 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { UUIDConverter } from '@/common/helper'; import { FileNapCatOneBotUUID } from '@/common/helper';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, ElementType, Peer, RawMessage } from '@/core/entities'; import { ChatType, Peer, RawMessage } from '@/core/entities';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
export interface GetFilePayload { export interface GetFilePayload {
@ -29,64 +29,64 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
payloadSchema: any = GetFileBase_PayloadSchema; payloadSchema: any = GetFileBase_PayloadSchema;
async _handle(payload: GetFilePayload): Promise<GetFileResponse> { async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
const NTQQFriendApi = this.core.apis.FriendApi;
const NTQQUserApi = this.core.apis.UserApi;
const NTQQMsgApi = this.core.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const NTQQGroupApi = this.core.apis.GroupApi;
const NTQQFileApi = this.core.apis.FileApi; const NTQQFileApi = this.core.apis.FileApi;
try {
const uuidData = UUIDConverter.decode(payload.file); const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
const peerUin = uuidData.high;
const msgId = uuidData.low; //接收消息标记模式
const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin); if (contextMsgFile) {
let peer: Peer | undefined; const { peer, msgId, elementId } = contextMsgFile;
//识别Peer
if (isGroup) { const downloadPath = await NTQQFileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: peerUin };
} const mixElement = (await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
const PeerUid = await NTQQUserApi.getUidByUinV2(peerUin); .find(msg => msg.msgId === msgId)?.elements.find(e => e.elementId === elementId);
if (PeerUid) { const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
const isBuddy = await NTQQFriendApi.isBuddy(PeerUid); if (!mixElementInner) throw new Error('element not found');
if (isBuddy) {
peer = { chatType: ChatType.KCHATTYPEC2C, peerUid: PeerUid }; const fileSize = mixElementInner.fileSize?.toString() || '';
} else { const fileName = mixElementInner.fileName || '';
peer = { chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: PeerUid };
}
}
if (!peer) {
throw new Error('chattype not support');
}
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]);
if (msgList.msgList.length == 0) {
throw new Error('msg not found');
}
const msg = msgList.msgList[0];
const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT);
if (!findEle) {
throw new Error('element not found');
}
const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', '');
const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0';
const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || '';
const res: GetFileResponse = { const res: GetFileResponse = {
file: downloadPath, file: downloadPath,
url: downloadPath, url: downloadPath,
file_size: fileSize, file_size: fileSize,
file_name: fileName, file_name: fileName,
}; };
if (/* enableLocalFile2Url && */ downloadPath) {
if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) {
try {
res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) {
throw new Error('文件下载失败. ' + e);
}
}
return res;
}
//群文件模式
const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(payload.file);
if (contextModelIdFile) {
const { peer, modelId } = contextModelIdFile;
const downloadPath = await NTQQFileApi.downloadFileForModelId(peer, modelId);
const res: GetFileResponse = {
file: downloadPath,
url: downloadPath,
file_size: '',
file_name: '',
};
if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) {
try { try {
res.base64 = await fs.readFile(downloadPath, 'base64'); res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) { } catch (e) {
throw new Error('文件下载失败. ' + e); throw new Error('文件下载失败. ' + e);
} }
} }
//不手动删除?文件持久化了
return res; return res;
} catch {
this.core.context.logger.logDebug('GetFileBase Mode - 1 Error');
} }
//搜索名字模式
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems; const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
if (NTSearchNameResult.length !== 0) { if (NTSearchNameResult.length !== 0) {
const MsgId = NTSearchNameResult[0].msgId; const MsgId = NTSearchNameResult[0].msgId;
@ -94,9 +94,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
if (NTSearchNameResult[0].chatType == ChatType.KCHATTYPEGROUP) { if (NTSearchNameResult[0].chatType == ChatType.KCHATTYPEGROUP) {
peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode }; peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode };
} }
if (!peer) { if (!peer) throw new Error('chattype not support');
throw new Error('chattype not support');
}
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList; const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList;
if (!msgList || msgList.length == 0) { if (!msgList || msgList.length == 0) {
throw new Error('msg not found'); throw new Error('msg not found');
@ -113,16 +111,16 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
file_size: NTSearchNameResult[0].fileSize.toString(), file_size: NTSearchNameResult[0].fileSize.toString(),
file_name: NTSearchNameResult[0].fileName, file_name: NTSearchNameResult[0].fileName,
}; };
if (/* enableLocalFile2Url && */ downloadPath) { if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) {
try { try {
res.base64 = await fs.readFile(downloadPath, 'base64'); res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) { } catch (e) {
throw new Error('文件下载失败. ' + e); throw new Error('文件下载失败. ' + e);
} }
} }
//不手动删除?文件持久化了
return res; return res;
} }
throw new Error('file not found'); throw new Error('file not found');
} }
} }

View File

@ -1,4 +1,4 @@
import { ChatType, GroupEssenceMsgRet, Peer } from '@/core'; import { ChatType, Peer } from '@/core';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
@ -18,42 +18,54 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupEssence extends BaseAction<Payload, any> { export class GetGroupEssence extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetEssenceMsg; actionName = ActionName.GoCQHTTP_GetEssenceMsg;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async msgSeqToMsgId(peer: Peer, msgSeq: string, msgRandom: string) {
const NTQQMsgApi = this.core.apis.MsgApi; private async msgSeqToMsgId(peer: Peer, msgSeq: string, msgRandom: string) {
const replyMsgList = (await NTQQMsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom); const replyMsgList = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom);
if (!replyMsgList) { if (!replyMsgList) {
return 0; return undefined;
} }
return MessageUnique.createUniqueMsgId(peer, replyMsgList.msgId); return {
id: MessageUnique.createUniqueMsgId(peer, replyMsgList.msgId),
msg: replyMsgList
};
} }
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQWebApi = this.core.apis.WebApi; const NTQQWebApi = this.core.apis.WebApi;
const NTQQGroupApi = this.core.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
//await NTQQGroupApi.fetchGroupEssenceList(payload.group_id.toString());
let peer = {
chatType: ChatType.KCHATTYPEGROUP,
peerUid: payload.group_id.toString(),
};
const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString()); const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString());
if (!ret) { if (!ret) {
throw new Error('获取失败'); throw new Error('获取失败');
} }
const Ob11Ret = await Promise.all(ret.data.msg_list.map(async (msg) => { return await Promise.all(ret.data.msg_list.map(async (msg) => {
let message_id = await this.msgSeqToMsgId(peer, msg.msg_seq.toString(), msg.msg_random.toString()); const msgOriginData = await this.msgSeqToMsgId({
if (message_id === 0) { chatType: ChatType.KCHATTYPEGROUP,
const data = JSON.stringify({ peerUid: payload.group_id.toString(),
msg_seq: msg.msg_seq.toString(), }, msg.msg_seq.toString(), msg.msg_random.toString());
msg_random: msg.msg_random.toString(), if (msgOriginData) {
group_id: payload.group_id.toString(), const { id: message_id, msg: rawMessage } = msgOriginData;
}); return {
const hash = crypto.createHash('md5').update(data).digest(); msg_seq: msg.msg_seq,
//设置第一个bit为0 保证shortId为正数 msg_random: msg.msg_random,
hash[0] &= 0x7f; sender_id: +msg.sender_uin,
const shortId = hash.readInt32BE(0); sender_nick: msg.sender_nick,
NTQQGroupApi.essenceLRU.set(shortId, data); operator_id: +msg.add_digest_uin,
message_id = shortId; operator_nick: msg.add_digest_nick,
message_id: message_id,
operator_time: msg.add_digest_time,
content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, 'array'))?.message
};
} }
const msgTempData = JSON.stringify({
msg_seq: msg.msg_seq.toString(),
msg_random: msg.msg_random.toString(),
group_id: payload.group_id.toString(),
});
const hash = crypto.createHash('md5').update(msgTempData).digest();
//设置第一个bit为0 保证shortId为正数
hash[0] &= 0x7f;
const shortId = hash.readInt32BE(0);
NTQQGroupApi.essenceLRU.set(shortId, msgTempData);
return { return {
msg_seq: msg.msg_seq, msg_seq: msg.msg_seq,
msg_random: msg.msg_random, msg_random: msg.msg_random,
@ -61,10 +73,27 @@ export class GetGroupEssence extends BaseAction<Payload, any> {
sender_nick: msg.sender_nick, sender_nick: msg.sender_nick,
operator_id: +msg.add_digest_uin, operator_id: +msg.add_digest_uin,
operator_nick: msg.add_digest_nick, operator_nick: msg.add_digest_nick,
message_id: message_id, message_id: shortId,
operator_time: msg.add_digest_time, operator_time: msg.add_digest_time,
content: msg.msg_content.map((msg) => {
if (msg.msg_type === 1) {
return {
type: 'text',
data: {
text: msg?.text
}
};
} else if (msg.msg_type === 3) {
return {
type: 'image',
data: {
url: msg?.image_url,
}
};
}
return undefined;
}).filter(e => e !== undefined),
}; };
})); }));
return Ob11Ret;
} }
} }

View File

@ -1,4 +1,4 @@
import { UUIDConverter } from '@/common/helper'; import { FileNapCatOneBotUUID } from '@/common/helper';
import { MessageUnique } from '@/common/message-unique'; import { MessageUnique } from '@/common/message-unique';
import { import {
AtType, AtType,
@ -98,14 +98,19 @@ export class OneBotMsgApi {
} }
}, },
picElement: async (element, msg) => { picElement: async (element, msg, elementWrapper) => {
try { try {
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
};
return { return {
type: OB11MessageDataType.image, type: OB11MessageDataType.image,
data: { data: {
file: element.fileName, file: element.fileName,
sub_type: element.picSubType, sub_type: element.picSubType,
file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId),
url: await this.core.apis.FileApi.getImageUrl(element), url: await this.core.apis.FileApi.getImageUrl(element),
file_size: element.fileSize, file_size: element.fileSize,
}, },
@ -117,6 +122,11 @@ export class OneBotMsgApi {
}, },
fileElement: async (element, msg, elementWrapper) => { fileElement: async (element, msg, elementWrapper) => {
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
};
await this.core.apis.FileApi.addFileCache( await this.core.apis.FileApi.addFileCache(
{ {
peerUid: msg.peerUid, peerUid: msg.peerUid,
@ -137,7 +147,7 @@ export class OneBotMsgApi {
file: element.fileName, file: element.fileName,
path: element.filePath, path: element.filePath,
url: element.filePath, url: element.filePath,
file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId),
file_size: element.fileSize, file_size: element.fileSize,
}, },
}; };
@ -184,11 +194,16 @@ export class OneBotMsgApi {
'0', '0',
'marketface', 'marketface',
); );
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
};
return { return {
type: OB11MessageDataType.image, type: OB11MessageDataType.image,
data: { data: {
file: 'marketface', file: 'marketface',
file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId),
path: elementWrapper.elementId, path: elementWrapper.elementId,
url: elementWrapper.elementId, url: elementWrapper.elementId,
}, },
@ -207,13 +222,21 @@ export class OneBotMsgApi {
this.core.context.logger.logError('获取不到引用的消息', element.replayMsgSeq); this.core.context.logger.logError('获取不到引用的消息', element.replayMsgSeq);
return null; return null;
} }
const createReplyData = (msgId: string): OB11MessageData => ({
type: OB11MessageDataType.reply,
data: {
id: MessageUnique.createUniqueMsgId(peer, msgId).toString(),
},
});
if (records.peerUin === '284840486') {
return createReplyData(records.msgId);
}
let replyMsg: RawMessage | undefined; let replyMsg: RawMessage | undefined;
// Attempt 1 // Attempt 1
replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount({ replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount(peer,element.replayMsgSeq, 1, true, true))
peerUid: msg.peerUid,
guildId: '',
chatType: msg.chatType,
}, element.replayMsgSeq, 1, true, true))
.msgList .msgList
.find(msg => msg.msgRandom === records.msgRandom); .find(msg => msg.msgRandom === records.msgRandom);
@ -221,7 +244,7 @@ export class OneBotMsgApi {
// Attempt 2 // Attempt 2
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replayMsgSeq)).msgList[0]; replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replayMsgSeq)).msgList[0];
if ((!replyMsg || records.msgRandom !== replyMsg.msgRandom) && msg.peerUin !== '284840486') { if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
// Attempt 3 // Attempt 3
const replyMsgList = (await NTQQMsgApi.getMsgExBySeq(peer, records.msgSeq)).msgList; const replyMsgList = (await NTQQMsgApi.getMsgExBySeq(peer, records.msgSeq)).msgList;
if (replyMsgList.length < 1) { if (replyMsgList.length < 1) {
@ -233,21 +256,16 @@ export class OneBotMsgApi {
} }
} }
return { return createReplyData(replyMsg.msgId);
type: OB11MessageDataType.reply,
data: {
id: MessageUnique.createUniqueMsgId({
peerUid: msg.peerUid,
guildId: '',
chatType: msg.chatType,
}, replyMsg.msgId).toString(),
},
};
}, },
videoElement: async (element, msg, elementWrapper) => { videoElement: async (element, msg, elementWrapper) => {
const NTQQFileApi = this.core.apis.FileApi; const NTQQFileApi = this.core.apis.FileApi;
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
};
//读取视频链接并兜底 //读取视频链接并兜底
let videoUrlWrappers: Awaited<ReturnType<typeof NTQQFileApi.getVideoUrl>> | undefined; let videoUrlWrappers: Awaited<ReturnType<typeof NTQQFileApi.getVideoUrl>> | undefined;
@ -302,13 +320,18 @@ export class OneBotMsgApi {
file: element.fileName, file: element.fileName,
path: videoDownUrl, path: videoDownUrl,
url: videoDownUrl, url: videoDownUrl,
file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId),
file_size: element.fileSize, file_size: element.fileSize,
}, },
}; };
}, },
pttElement: async (element, msg, elementWrapper) => { pttElement: async (element, msg, elementWrapper) => {
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
};
await this.core.apis.FileApi.addFileCache( await this.core.apis.FileApi.addFileCache(
{ {
peerUid: msg.peerUid, peerUid: msg.peerUid,
@ -328,7 +351,7 @@ export class OneBotMsgApi {
data: { data: {
file: element.fileName, file: element.fileName,
path: element.filePath, path: element.filePath,
file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId),
file_size: element.fileSize, file_size: element.fileSize,
}, },
}; };

View File

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

View File

@ -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("V2.2.21", "napcat-update-button", "secondary") SettingButton("V2.2.22", "napcat-update-button", "secondary")
) )
]), ]),
SettingList([ SettingList([