diff --git a/src/main/main.ts b/src/main/main.ts index a1b1032..c103f37 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -198,6 +198,13 @@ function onLoad() { postOb11Event(privateEvent) } }) + // OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => { + // log(message) + // if (friendAddEvent) { + // // log("post friend add event", friendAddEvent); + // postOb11Event(friendAddEvent) + // } + // }) } } @@ -216,7 +223,7 @@ function onLoad() { pokeEvent = new OB11GroupPokeEvent(parseInt(id)) } else { - pokeEvent = new OB11FriendPokeEvent(parseInt(id)) + pokeEvent = new OB11FriendPokeEvent(parseInt(selfInfo.uin), parseInt(id)) } postOb11Event(pokeEvent) }) @@ -311,34 +318,36 @@ function onLoad() { // if (notify.user2.uid) { // member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid); // } - if ( - [GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes( - notify.type, - ) - ) { - const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid) - log('有管理员变动通知') - refreshGroupMembers(notify.group.groupCode).then() - let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent() - groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode) - log('开始获取变动的管理员') - if (member1) { - log('变动管理员获取成功') - groupAdminNoticeEvent.user_id = parseInt(member1.uin) - groupAdminNoticeEvent.sub_type = [ - GroupNotifyTypes.ADMIN_UNSET, - GroupNotifyTypes.ADMIN_UNSET_OTHER, - ].includes(notify.type) - ? 'unset' - : 'set' - // member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal; - postOb11Event(groupAdminNoticeEvent, true) - } - else { - log('获取群通知的成员信息失败', notify, getGroup(notify.group.groupCode)) - } - } - else if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) { + // 原本的群管变更通知事件处理 + // if ( + // [GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes( + // notify.type, + // ) + // ) { + // const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid) + // log('有管理员变动通知') + // refreshGroupMembers(notify.group.groupCode).then() + // let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent() + // groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode) + // log('开始获取变动的管理员') + // if (member1) { + // log('变动管理员获取成功') + // groupAdminNoticeEvent.user_id = parseInt(member1.uin) + // groupAdminNoticeEvent.sub_type = [ + // GroupNotifyTypes.ADMIN_UNSET, + // GroupNotifyTypes.ADMIN_UNSET_OTHER, + // ].includes(notify.type) + // ? 'unset' + // : 'set' + // // member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal; + // postOb11Event(groupAdminNoticeEvent, true) + // } + // else { + // log('获取群通知的成员信息失败', notify, getGroup(notify.group.groupCode)) + // } + // } + // else + if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) { log('有成员退出通知', notify) try { const member1 = await NTQQUserApi.getUserDetailInfo(notify.user1.uid) diff --git a/src/ntqqapi/api/group.ts b/src/ntqqapi/api/group.ts index 06d00c5..6617dcc 100644 --- a/src/ntqqapi/api/group.ts +++ b/src/ntqqapi/api/group.ts @@ -5,6 +5,7 @@ import { deleteGroup, uidMaps } from '../../common/data' import { dbUtil } from '../../common/db' import { log } from '../../common/utils/log' import { NTQQWindowApi, NTQQWindows } from './window' +import { wrapperApi } from '../native/wrapper' export class NTQQGroupApi { @@ -282,4 +283,28 @@ export class NTQQGroupApi { }) } static publishGroupBulletin(groupQQ: string, title: string, content: string) {} + static async removeGroupEssence(GroupCode: string, msgId: string) { + // 代码没测过 + // 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom + let MsgData = await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false); + let param = { + groupCode: GroupCode, + msgRandom: parseInt(MsgData.msgList[0].msgRandom), + msgSeq: parseInt(MsgData.msgList[0].msgSeq) + }; + // GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数 + return wrapperApi.NodeIQQNTWrapperSession.getGroupService().removeGroupEssence(param); + } + static async addGroupEssence(GroupCode: string, msgId: string) { + // 代码没测过 + // 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom + let MsgData = await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false); + let param = { + groupCode: GroupCode, + msgRandom: parseInt(MsgData.msgList[0].msgRandom), + msgSeq: parseInt(MsgData.msgList[0].msgSeq) + }; + // GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数 + return wrapperApi.NodeIQQNTWrapperSession.getGroupService().addGroupEssence(param); + } } diff --git a/src/ntqqapi/api/msg.ts b/src/ntqqapi/api/msg.ts index 54ca551..1bd2da8 100644 --- a/src/ntqqapi/api/msg.ts +++ b/src/ntqqapi/api/msg.ts @@ -1,22 +1,17 @@ import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall' -import { ChatType, RawMessage, SendMessageElement } from '../types' +import { ChatType, RawMessage, SendMessageElement, Peer } from '../types' import { dbUtil } from '../../common/db' import { selfInfo } from '../../common/data' import { ReceiveCmdS, registerReceiveHook } from '../hook' import { log } from '../../common/utils/log' import { sleep } from '../../common/utils/helper' import { isQQ998 } from '../../common/utils' +import { wrapperApi } from '@/ntqqapi/native/wrapper' export let sendMessagePool: Record void) | null> = {} // peerUid: callbackFunc export let sentMessages: Record = {} // msgId: RawMessage -export interface Peer { - chatType: ChatType - peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串 - guildId?: '' -} - async function sendWaiter(peer: Peer, waitComplete = true, timeout: number = 10000) { // 等待上一个相同的peer发送完 const peerUid = peer.peerUid @@ -293,4 +288,7 @@ export class NTQQMsgApi { }) }) } + static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) { + return await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z); + } } diff --git a/src/ntqqapi/hook.ts b/src/ntqqapi/hook.ts index ca2708d..3e9fee6 100644 --- a/src/ntqqapi/hook.ts +++ b/src/ntqqapi/hook.ts @@ -23,6 +23,7 @@ import { log } from '@/common/utils' import { isNumeric, sleep } from '@/common/utils' import { OB11Constructor } from '../onebot11/constructor' import { OB11GroupCardEvent } from '../onebot11/event/notice/OB11GroupCardEvent' +import { OB11GroupAdminNoticeEvent } from '../onebot11/event/notice/OB11GroupAdminNoticeEvent' export let hookApiCallbacks: Record void> = {} @@ -369,6 +370,13 @@ export async function startHook() { postOb11Event( new OB11GroupCardEvent(parseInt(groupCode), parseInt(member.uin), member.cardName, existMember.cardName), ) + } else if (member.role != existMember.role) { + log('有管理员变动通知') + let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent() + groupAdminNoticeEvent.group_id = parseInt(groupCode) + groupAdminNoticeEvent.user_id = parseInt(member.uin) + groupAdminNoticeEvent.sub_type = member.role == GroupMemberRole.admin ? 'set' : 'unset' + postOb11Event(groupAdminNoticeEvent, true) } Object.assign(existMember, member) } diff --git a/src/ntqqapi/types/msg.ts b/src/ntqqapi/types/msg.ts index 1e74520..e50295f 100644 --- a/src/ntqqapi/types/msg.ts +++ b/src/ntqqapi/types/msg.ts @@ -415,3 +415,9 @@ export interface RawMessage { multiForwardMsgElement: MultiForwardMsgElement }[] } + +export interface Peer { + chatType: ChatType; + peerUid: string; // 如果是群聊uid为群号,私聊uid就是加密的字符串 + guildId?: string; +} \ No newline at end of file diff --git a/src/onebot11/action/go-cqhttp/DelEssenceMsg.ts b/src/onebot11/action/go-cqhttp/DelEssenceMsg.ts new file mode 100644 index 0000000..2bc5c3b --- /dev/null +++ b/src/onebot11/action/go-cqhttp/DelEssenceMsg.ts @@ -0,0 +1,24 @@ + +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '../../../ntqqapi/api/group' +import { dbUtil } from '@/common/db'; + +interface Payload { + message_id: number | string; +} + +export default class GoCQHTTPDelEssenceMsg extends BaseAction { + actionName = ActionName.GoCQHTTP_DelEssenceMsg; + + protected async _handle(payload: Payload): Promise { + const msg = await dbUtil.getMsgByShortId(parseInt(payload.message_id.toString())); + if (!msg) { + throw new Error('msg not found'); + } + return await NTQQGroupApi.removeGroupEssence( + msg.peerUid, + msg.msgId + ); + } +} diff --git a/src/onebot11/action/go-cqhttp/SetEssenceMsg.ts b/src/onebot11/action/go-cqhttp/SetEssenceMsg.ts new file mode 100644 index 0000000..682eddd --- /dev/null +++ b/src/onebot11/action/go-cqhttp/SetEssenceMsg.ts @@ -0,0 +1,23 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '../../../ntqqapi/api/group' +import { dbUtil } from '@/common/db'; + +interface Payload { + message_id: number | string; +} + +export default class GoCQHTTPSetEssenceMsg extends BaseAction { + actionName = ActionName.GoCQHTTP_SetEssenceMsg; + + protected async _handle(payload: Payload): Promise { + const msg = await dbUtil.getMsgByShortId(parseInt(payload.message_id.toString())); + if (!msg) { + throw new Error('msg not found'); + } + return await NTQQGroupApi.addGroupEssence( + msg.peerUid, + msg.msgId + ); + } +} diff --git a/src/onebot11/action/index.ts b/src/onebot11/action/index.ts index ad57dc1..a0a8b02 100644 --- a/src/onebot11/action/index.ts +++ b/src/onebot11/action/index.ts @@ -50,8 +50,11 @@ import { ForwardFriendSingleMsg, ForwardGroupSingleMsg } from './msg/ForwardSing import { GetGroupEssence } from './group/GetGroupEssence' import { GetGroupHonorInfo } from './group/GetGroupHonorInfo' import { GoCQHTTHandleQuickOperation } from './go-cqhttp/QuickOperation' +import GoCQHTTPSetEssenceMsg from './go-cqhttp/SetEssenceMsg' +import GoCQHTTPDelEssenceMsg from './go-cqhttp/DelEssenceMsg' import GetEvent from './llonebot/GetEvent' + export const actionHandlers = [ new GetFile(), new Debug(), @@ -108,7 +111,9 @@ export const actionHandlers = [ new GoCQHTTPUploadPrivateFile(), new GoCQHTTPGetGroupMsgHistory(), new GoCQHTTGetForwardMsgAction(), - new GoCQHTTHandleQuickOperation() + new GoCQHTTHandleQuickOperation(), + new GoCQHTTPSetEssenceMsg(), + new GoCQHTTPDelEssenceMsg() ] function initActionMap() { diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts index f5b1abb..88cdd0f 100644 --- a/src/onebot11/action/types.ts +++ b/src/onebot11/action/types.ts @@ -71,4 +71,6 @@ export enum ActionName { GoCQHTTP_GetEssenceMsg = "get_essence_msg_list", GoCQHTTP_HandleQuickOperation = ".handle_quick_operation", GetGroupHonorInfo = "get_group_honor_info", + GoCQHTTP_SetEssenceMsg = 'set_essence_msg', + GoCQHTTP_DelEssenceMsg = 'delete_essence_msg', } diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index addc4fb..eaae427 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -15,6 +15,7 @@ import { FaceIndex, GrayTipElementSubType, Group, + Peer, GroupMember, PicType, RawMessage, @@ -34,6 +35,7 @@ import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNotice import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent' import { NTQQUserApi } from '../ntqqapi/api/user' import { NTQQFileApi } from '../ntqqapi/api/file' +import { NTQQMsgApi } from '../ntqqapi/api/msg' import { calcQQLevel } from '../common/utils/qqlevel' import { log } from '../common/utils/log' import { sleep } from '../common/utils/helper' @@ -49,6 +51,7 @@ import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoti import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent' import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent' import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent'; +import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent'; let lastRKeyUpdateTime = 0 @@ -321,11 +324,11 @@ export class OB11Constructor { if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) { //判断业务类型 //Poke事件 - let pokedetail: any[] = json.items; + const pokedetail: any[] = json.items; //筛选item带有uid的元素 - pokedetail = pokedetail.filter(item => item.uid); - if (pokedetail.length == 2) { - return new OB11FriendPokeEvent(parseInt((uidMaps[pokedetail[0].uid])!), parseInt((uidMaps[pokedetail[1].uid]))); + const poke_uid = pokedetail.filter(item => item.uid); + if (poke_uid.length == 2) { + return new OB11FriendPokeEvent(parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail); } } //下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE @@ -526,20 +529,41 @@ export class OB11Constructor { if (grayTipElement.jsonGrayTipElement.busiId == 1061) { //判断业务类型 //Poke事件 - let pokedetail: any[] = json.items; + const pokedetail: any[] = json.items; //筛选item带有uid的元素 - pokedetail = pokedetail.filter(item => item.uid); - if (pokedetail.length == 2) { - return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[pokedetail[0].uid])!), parseInt((uidMaps[pokedetail[1].uid]))); + const poke_uid = pokedetail.filter(item => item.uid); + if (poke_uid.length == 2) { + return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail); } } - const memberUin = json.items[1].param[0] - const title = json.items[3].txt - log('收到群成员新头衔消息', json) - getGroupMember(msg.peerUid, memberUin).then((member) => { - member.memberSpecialTitle = title - }) - return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title) + if (grayTipElement.jsonGrayTipElement.busiId == 2401) { + log('收到群精华消息', json) + const searchParams = new URL(json.items[0].jp).searchParams; + const msgSeq = searchParams.get('msgSeq')!; + const Group = searchParams.get('groupCode'); + const Businessid = searchParams.get('businessid'); + const Peer: Peer = { + guildId: '', + chatType: ChatType.group, + peerUid: Group! + }; + const msgList = (await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true)).msgList; + // (待解决) getMsgByLongId 拿到的 ShortId 经常跟实际 Msg 对不上(但msgId是一致的)。 + // 不过引用消息拿到的 ShortId 是对的。 + //console.log("原始消息: ", msgList); + //console.log("本地缓存: ", await dbUtil.getMsgByLongId(msgList[0].msgId)); + return new OB11GroupEssenceEvent(parseInt(msg.peerUid), Number(((await dbUtil.getMsgByLongId(msgList[0].msgId)).msgShortId)!), parseInt(msgList[0].senderUin)); + // 获取MsgSeq+Peer可获取具体消息 + } + if (grayTipElement.jsonGrayTipElement.busiId == 2407) { + const memberUin = json.items[1].param[0] + const title = json.items[3].txt + log('收到群成员新头衔消息', json) + getGroupMember(msg.peerUid, memberUin).then((member) => { + member.memberSpecialTitle = title + }) + return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title) + } } } } diff --git a/src/onebot11/event/notice/OB11GroupEssenceEvent.ts b/src/onebot11/event/notice/OB11GroupEssenceEvent.ts new file mode 100644 index 0000000..ae1053e --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupEssenceEvent.ts @@ -0,0 +1,14 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; +export class OB11GroupEssenceEvent extends OB11GroupNoticeEvent { + notice_type = 'essence'; + message_id: number; + sender_id: number; + sub_type: 'add' | 'delete' = 'add'; + + constructor(groupId: number, message_id: number, sender_id: number) { + super(); + this.group_id = groupId; + this.message_id = message_id; + this.sender_id = sender_id; + } +} diff --git a/src/onebot11/event/notice/OB11PokeEvent.ts b/src/onebot11/event/notice/OB11PokeEvent.ts index 68adb78..0f98ef6 100644 --- a/src/onebot11/event/notice/OB11PokeEvent.ts +++ b/src/onebot11/event/notice/OB11PokeEvent.ts @@ -5,25 +5,28 @@ import { OB11BaseEvent } from '../OB11BaseEvent' class OB11PokeEvent extends OB11BaseNoticeEvent { notice_type = 'notify' sub_type = 'poke' - target_id = parseInt(selfInfo.uin) + target_id = 0 user_id: number + raw_message: any } export class OB11FriendPokeEvent extends OB11PokeEvent { - constructor(user_id: number, target_id: number=0) { + + constructor(user_id: number, target_id: number, raw_message: any) { super(); this.target_id = target_id; this.user_id = user_id; + this.raw_message = raw_message; } } export class OB11GroupPokeEvent extends OB11PokeEvent { group_id: number - - constructor(group_id: number, user_id: number = 0, target_id: number = 0) { + constructor(group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) { super() this.group_id = group_id this.target_id = target_id this.user_id = user_id + this.raw_message = raw_message } }