import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/core/entities'; import { InstanceContext, NapCatCore } from '@/core'; import { GeneralCallResult } from '@/core/services/common'; export class NTQQMsgApi { // 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 // 其实以官方文档为准是最好的,https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType context: InstanceContext; core: NapCatCore; constructor(context: InstanceContext, core: NapCatCore) { this.context = context; this.core = core; } async getAioFirstViewLatestMsgs(peer: Peer, MsgCount: number) { return this.context.session.getMsgService().getAioFirstViewLatestMsgs(peer, MsgCount); } async getLatestDbMsgs(peer: Peer, MsgCount: number) { return this.context.session.getMsgService().getLatestDbMsgs(peer, MsgCount); } async FetchLongMsg(peer: Peer, msgId: string) { return this.context.session.getMsgService().fetchLongMsg(peer, msgId); } async sendShowInputStatusReq(peer: Peer, eventType: number) { return this.context.session.getMsgService().sendShowInputStatusReq(peer.chatType, eventType, peer.peerUid); } async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) { //注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, count); } async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) { // 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 // 其实以官方文档为准是最好的,https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType emojiId = emojiId.toString(); return this.context.session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set); } async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise { return this.context.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId); } async ForwardMsg(peer: Peer, msgIds: string[]) { return this.context.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map()); } async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) { if (!peer) throw new Error('peer is not allowed'); if (!msgIds) throw new Error('msgIds is not allowed'); //MliKiowa: 参数不合规会导致NC异常崩溃 原因是TX未对进入参数判断 对应Android标记@NotNull AndroidJADX分析可得 return await this.context.session.getMsgService().getMsgsByMsgId(peer, msgIds); } async getSingleMsg(peer: Peer, seq: string) { return await this.context.session.getMsgService().getSingleMsg(peer, seq); } async fetchFavEmojiList(num: number) { return this.context.session.getMsgService().fetchFavEmojiList('', num, true, true); } async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { chatInfo: peer, filterMsgType: [], filterSendersUid: [], filterMsgToTime: '0', filterMsgFromTime: '0', isReverseOrder: false, isIncludeCurrent: true, pageLimit: 1, }); } async queryMsgsWithFilterExWithSeqV2(peer: Peer, msgSeq: string, MsgTime: string, SendersUid: string[]) { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { chatInfo: peer, filterMsgType: [], filterSendersUid: SendersUid, filterMsgToTime: MsgTime, filterMsgFromTime: MsgTime, isReverseOrder: false, isIncludeCurrent: true, pageLimit: 1, }); } async queryFirstMsgBySeq(peer: Peer, msgSeq: string) { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { chatInfo: peer, filterMsgType: [], filterSendersUid: [], filterMsgToTime: '0', filterMsgFromTime: '0', isReverseOrder: true, isIncludeCurrent: true, pageLimit: 1, }); } async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) { return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z); } async getMsgBySeqList(peer: Peer, msgSeqList: string[]) { //坏的 return await this.context.session.getMsgService().getMsgsBySeqList(peer, msgSeqList); } async getMsgBySeqExFirstMsg(peer: Peer, rootMsgId: string, replyMsgId: string) { let reply = await this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, rootMsgId, replyMsgId); console.log(reply); } async getMsgExBySeq(peer: Peer, msgSeq: string) { const DateNow = Math.floor(Date.now() / 1000); const filterMsgFromTime = (DateNow - 300).toString(); const filterMsgToTime = DateNow.toString(); return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa filterMsgType: [], filterSendersUid: [], filterMsgToTime: filterMsgToTime, filterMsgFromTime: filterMsgFromTime, isReverseOrder: false, isIncludeCurrent: true, pageLimit: 100, }); } async setMsgRead(peer: Peer) { return this.context.session.getMsgService().setMsgRead(peer); } async getGroupFileList(GroupCode: string, params: GetFileListParam) { const [, groupFileListResult] = await this.core.eventWrapper.callNormalEventV2( 'NodeIKernelRichMediaService/getGroupFileList', 'NodeIKernelMsgListener/onGroupFileInfoUpdate', [ GroupCode, params, ], () => true, () => true, // Todo: 应当通过 groupFileListResult 判断 1, 5000, ); return groupFileListResult.item; } async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) { // 消息时间从旧到新 return this.context.session.getMsgService().getMsgsIncludeSelf(peer, msgId, count, isReverseOrder); } async recallMsg(peer: Peer, msgIds: string[]) { await this.context.session.getMsgService().recallMsg({ chatType: peer.chatType, peerUid: peer.peerUid, }, msgIds); } async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) { return this.context.session.getMsgService().prepareTempChat({ chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: toUserUid, peerNickname: nickname, fromGroupCode: GroupCode, sig: '', selfPhone: '', selfUid: this.core.selfInfo.uid, gameSession: { nickname: '', gameAppId: '', selfTinyId: '', peerRoleId: '', peerOpenId: '', }, }); } async getTempChatInfo(chatType: ChatType, peerUid: string) { return this.context.session.getMsgService().getTempChatInfo(chatType, peerUid); } async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) { //唉?!我有个想法 if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') { const member = await this.core.apis.GroupApi.getGroupMember(peer.guildId, peer.peerUid!); if (member) { await this.PrepareTempChat(peer.peerUid, peer.guildId, member.nick); } } const msgId = await this.generateMsgUniqueId(peer.chatType, await this.getServerTime()); peer.guildId = msgId; const [, msgList] = await this.core.eventWrapper.callNormalEventV2( 'NodeIKernelMsgService/sendMsg', 'NodeIKernelMsgListener/onMsgInfoListUpdate', [ '0', peer, msgElements, new Map(), ], (ret) => ret.result === 0, msgRecords => { for (const msgRecord of msgRecords) { if (msgRecord.guildId === msgId && msgRecord.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS) { return true; } } return false; }, 1, timeout, ); return msgList.find(msgRecord => msgRecord.guildId === msgId); } async generateMsgUniqueId(chatType: number, time: string) { return this.context.session.getMsgService().generateMsgUniqueId(chatType, time); } async getServerTime() { return this.context.session.getMSFService().getServerTime(); } async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) { return this.context.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map()); } async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise { const msgInfos = msgIds.map(id => { return { msgId: id, senderShowName: this.core.selfInfo.nick }; }); const [, msgList] = await this.core.eventWrapper.callNormalEventV2( 'NodeIKernelMsgService/multiForwardMsgWithComment', 'NodeIKernelMsgListener/onMsgInfoListUpdate', [ msgInfos, srcPeer, destPeer, [], new Map(), ], () => true, (msgRecords) => msgRecords.some( msgRecord => msgRecord.peerUid === destPeer.peerUid && msgRecord.senderUid === this.core.selfInfo.uid ), ); for (const msg of msgList) { const arkElement = msg.elements.find(ele => ele.arkElement); if (!arkElement) { continue; } const forwardData: any = JSON.parse(arkElement.arkElement?.bytesData ?? ''); if (forwardData.app != 'com.tencent.multimsg') { continue; } if (msg.peerUid == destPeer.peerUid && msg.senderUid == this.core.selfInfo.uid) { return msg; } } throw new Error('转发消息超时'); } async markAllMsgAsRead() { return this.context.session.getMsgService().setAllC2CAndGroupMsgRead(); } }