From c6342b80a7029592ed424b0bcff95faa12597597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Wed, 28 Aug 2024 20:51:59 +0800 Subject: [PATCH 1/2] release: 2.2.21 --- manifest.json | 2 +- package.json | 2 +- src/common/version.ts | 2 +- src/core/apis/group.ts | 20 ++++++- src/core/apis/webapi.ts | 62 +++++++++++----------- src/onebot/action/group/DelEssenceMsg.ts | 8 ++- src/onebot/action/group/GetGroupEssence.ts | 55 ++++++++++++++++--- src/webui/ui/NapCat.ts | 2 +- static/assets/renderer.js | 2 +- 9 files changed, 109 insertions(+), 46 deletions(-) diff --git a/manifest.json b/manifest.json index 12c9dbdd..90351e9e 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "NapCatQQ", "slug": "NapCat.Framework", "description": "高性能的 OneBot 11 协议实现", - "version": "2.2.20", + "version": "2.2.21", "icon": "./logo.png", "authors": [ { diff --git a/package.json b/package.json index fa7bb8fa..64d9fc7e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "napcat", "private": true, "type": "module", - "version": "2.2.20", + "version": "2.2.21", "scripts": { "build:framework": "vite build --mode framework", "build:shell": "vite build --mode shell", diff --git a/src/common/version.ts b/src/common/version.ts index 0b42754f..32cac52f 100644 --- a/src/common/version.ts +++ b/src/common/version.ts @@ -1 +1 @@ -export const napCatVersion = '2.2.20'; +export const napCatVersion = '2.2.21'; diff --git a/src/core/apis/group.ts b/src/core/apis/group.ts index c5f388fd..7f3a16c5 100644 --- a/src/core/apis/group.ts +++ b/src/core/apis/group.ts @@ -12,6 +12,7 @@ import { NapCatCore, } from '@/core'; import { isNumeric, runAllWithTimeout } from '@/common/helper'; +import { LimitedHashTable } from '@/common/message-unique'; export class NTQQGroupApi { context: InstanceContext; @@ -19,6 +20,7 @@ export class NTQQGroupApi { groupCache: Map = new Map(); groupMemberCache: Map> = new Map>(); groups: Group[] = []; + essenceLRU = new LimitedHashTable(1000); constructor(context: InstanceContext, core: NapCatCore) { this.context = context; @@ -33,6 +35,14 @@ export class NTQQGroupApi { } this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`); } + async fetchGroupEssenceList(groupCode: string) { + const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!; + return this.context.session.getGroupService().fetchGroupEssenceList({ + groupCode: groupCode, + pageStart: 0, + pageLimit: 300 + }, pskey); + } async clearGroupNotifiesUnreadCount(unk: boolean) { return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(unk); } @@ -273,7 +283,15 @@ export class NTQQGroupApi { //应该是直接返回不需要Listener的 未经测试 需测试再发布 return this.context.session.getGroupService().quitGroupV2(param); } - + async removeGroupEssenceBySeq(GroupCode: string, msgRandom: string, msgSeq: string) { + const param = { + groupCode: GroupCode, + msgRandom: parseInt(msgRandom), + msgSeq: parseInt(msgSeq), + }; + // GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数 + return this.context.session.getGroupService().removeGroupEssence(param); + } async removeGroupEssence(GroupCode: string, msgId: string) { // 代码没测过 // 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom diff --git a/src/core/apis/webapi.ts b/src/core/apis/webapi.ts index b75c9770..d43d9190 100644 --- a/src/core/apis/webapi.ts +++ b/src/core/apis/webapi.ts @@ -27,7 +27,7 @@ export class NTQQWebApi { msg_random: msgRandom, target_group_code: targetGroupCode, }).toString() - }`; + }`; try { return RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); } catch (e) { @@ -35,19 +35,17 @@ export class NTQQWebApi { } } - async getGroupEssenceMsg(GroupCode: string, page_start: string) { + async getGroupEssenceMsg(GroupCode: string) { const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${new URLSearchParams({ bkn: this.getBknFromCookie(cookieObject), group_code: GroupCode, - page_start, - page_limit: '20', }).toString() - }`; + }`; let ret; try { ret = await RequestUtil.HttpGetJson - (url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); + (url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); } catch { return undefined; } @@ -63,14 +61,14 @@ export class NTQQWebApi { const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const retList: Promise[] = []; const fastRet = await RequestUtil.HttpGetJson - (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({ - st: '0', - end: '40', - sort: '1', - gc: GroupCode, - bkn: this.getBknFromCookie(cookieObject), - }).toString() - }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); + (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({ + st: '0', + end: '40', + sort: '1', + gc: GroupCode, + bkn: this.getBknFromCookie(cookieObject), + }).toString() + }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) { return []; } else { @@ -83,14 +81,14 @@ export class NTQQWebApi { //遍历批量请求 for (let i = 2; i <= PageNum; i++) { const ret = RequestUtil.HttpGetJson - (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({ - st: ((i - 1) * 40).toString(), - end: (i * 40).toString(), - sort: '1', - gc: GroupCode, - bkn: this.getBknFromCookie(cookieObject), - }).toString() - }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); + (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({ + st: ((i - 1) * 40).toString(), + end: (i * 40).toString(), + sort: '1', + gc: GroupCode, + bkn: this.getBknFromCookie(cookieObject), + }).toString() + }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); retList.push(ret); } //批量等待 @@ -123,15 +121,15 @@ export class NTQQWebApi { let ret: any = undefined; try { ret = await RequestUtil.HttpGetJson - (`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({ - bkn: this.getBknFromCookie(cookieObject), - qid: GroupCode, - text: Content, - pinned: '0', - type: '1', - settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}', - }).toString() - }`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); + (`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({ + bkn: this.getBknFromCookie(cookieObject), + qid: GroupCode, + text: Content, + pinned: '0', + type: '1', + settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}', + }).toString() + }`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); return ret; } catch (e) { return undefined; @@ -162,7 +160,7 @@ export class NTQQWebApi { gc: Internal_groupCode, type: Internal_type.toString(), }).toString() - }`; + }`; let resJson; try { const res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); diff --git a/src/onebot/action/group/DelEssenceMsg.ts b/src/onebot/action/group/DelEssenceMsg.ts index c951cbdb..f3c43690 100644 --- a/src/onebot/action/group/DelEssenceMsg.ts +++ b/src/onebot/action/group/DelEssenceMsg.ts @@ -20,7 +20,13 @@ export default class DelEssenceMsg extends BaseAction { async _handle(payload: Payload): Promise { const NTQQGroupApi = this.core.apis.GroupApi; const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id); - if (!msg) throw new Error('msg not found'); + const NTQQWebApi = this.core.apis.WebApi; + if (!msg) { + const data = NTQQGroupApi.essenceLRU.getValue(+payload.message_id); + if(!data) throw new Error('消息不存在'); + const { msg_seq, msg_random, group_id } = JSON.parse(data) as { msg_seq: string, msg_random: string, group_id: string }; + return await NTQQGroupApi.removeGroupEssenceBySeq(group_id, msg_seq, msg_random); + } return await NTQQGroupApi.removeGroupEssence( msg.Peer.peerUid, msg.MsgId, diff --git a/src/onebot/action/group/GetGroupEssence.ts b/src/onebot/action/group/GetGroupEssence.ts index 74c52aa6..0e529e73 100644 --- a/src/onebot/action/group/GetGroupEssence.ts +++ b/src/onebot/action/group/GetGroupEssence.ts @@ -1,29 +1,70 @@ -import { GroupEssenceMsgRet } from '@/core'; +import { ChatType, GroupEssenceMsgRet, Peer } from '@/core'; import BaseAction from '../BaseAction'; import { ActionName } from '../types'; import { FromSchema, JSONSchema } from 'json-schema-to-ts'; +import { MessageUnique } from '@/common/message-unique'; +import crypto from 'crypto'; const SchemaData = { type: 'object', properties: { - group_id: { type: ['number', 'string'] }, - pages: { type: ['number', 'string'] }, + group_id: { type: ['number', 'string'] } }, required: ['group_id'], } as const satisfies JSONSchema; type Payload = FromSchema; -export class GetGroupEssence extends BaseAction { +export class GetGroupEssence extends BaseAction { actionName = ActionName.GoCQHTTP_GetEssenceMsg; payloadSchema = SchemaData; - + async msgSeqToMsgId(peer: Peer, msgSeq: string, msgRandom: string) { + const NTQQMsgApi = this.core.apis.MsgApi; + const replyMsgList = (await NTQQMsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom); + if (!replyMsgList) { + return 0; + } + return MessageUnique.createUniqueMsgId(peer, replyMsgList.msgId); + } async _handle(payload: Payload) { const NTQQWebApi = this.core.apis.WebApi; - const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString(), (+(payload.pages ?? 0)).toString()); + 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()); if (!ret) { throw new Error('获取失败'); } - return ret; + const Ob11Ret = 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()); + if (message_id === 0) { + const data = 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(data).digest(); + //设置第一个bit为0 保证shortId为正数 + hash[0] &= 0x7f; + const shortId = hash.readInt32BE(0); + NTQQGroupApi.essenceLRU.set(shortId, data); + message_id = shortId; + } + return { + msg_seq: msg.msg_seq, + msg_random: msg.msg_random, + sender_id: +msg.sender_uin, + sender_nick: msg.sender_nick, + operator_id: +msg.add_digest_uin, + operator_nick: msg.add_digest_nick, + message_id: message_id, + operator_time: msg.add_digest_time, + }; + })); + return Ob11Ret; } } diff --git a/src/webui/ui/NapCat.ts b/src/webui/ui/NapCat.ts index 73a09ed6..d174653b 100644 --- a/src/webui/ui/NapCat.ts +++ b/src/webui/ui/NapCat.ts @@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) { SettingItem( 'Napcat', undefined, - SettingButton('V2.2.20', 'napcat-update-button', 'secondary'), + SettingButton('V2.2.21', 'napcat-update-button', 'secondary'), ), ]), SettingList([ diff --git a/static/assets/renderer.js b/static/assets/renderer.js index 760add0e..45e01aec 100644 --- a/static/assets/renderer.js +++ b/static/assets/renderer.js @@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) { SettingItem( 'Napcat', void 0, - SettingButton("V2.2.20", "napcat-update-button", "secondary") + SettingButton("V2.2.21", "napcat-update-button", "secondary") ) ]), SettingList([ From 7f9da8cc2dc45418a0027c61296e14e149b5c2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Wed, 28 Aug 2024 21:19:17 +0800 Subject: [PATCH 2/2] feat: support folder_id --- src/onebot/action/file/GetGroupFileList.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/onebot/action/file/GetGroupFileList.ts b/src/onebot/action/file/GetGroupFileList.ts index dbb7ff4f..40c12648 100644 --- a/src/onebot/action/file/GetGroupFileList.ts +++ b/src/onebot/action/file/GetGroupFileList.ts @@ -6,8 +6,9 @@ const SchemaData = { type: 'object', properties: { group_id: { type: ['string', 'number'] }, - start_index: { type: 'number' }, - file_count: { type: 'number' }, + start_index: { type: ['string', 'number'] }, + file_count: { type: ['string', 'number'] }, + folder_id: { type: ['string', 'number'] }, }, required: ['group_id', 'start_index', 'file_count'], } as const satisfies JSONSchema; @@ -20,12 +21,19 @@ export class GetGroupFileList extends BaseAction async _handle(payload: Payload) { const NTQQMsgApi = this.core.apis.MsgApi; + let param = {}; + if (payload.folder_id) { + param = { + folderId: payload.folder_id.toString(), + }; + } const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), { sortType: 1, - fileCount: payload.file_count, - startIndex: payload.start_index, + fileCount: +payload.file_count, + startIndex: +payload.start_index, sortOrder: 2, showOnlinedocFolder: 0, + ...param }).catch((e) => { return []; });