Compare commits

..

30 Commits

Author SHA1 Message Date
idranme
79c5041216 Merge pull request #318 from LLOneBot/dev 2024-08-04 18:07:03 +08:00
idranme
8fb53260ab chore: v3.27.4 2024-08-04 10:05:03 +00:00
idranme
07d9ac823a Merge pull request #317 from LLOneBot/dev
chore: v3.27.4
2024-08-04 17:48:24 +08:00
linyuchen
296cd4d0a3 Merge pull request #315 from idranme/main
feat: at segment add name
2024-08-02 23:11:14 +08:00
linyuchen
e77a2ca34a Merge pull request #311 from cnxysoft/dev
BUG修复
2024-08-02 23:09:35 +08:00
idranme
406e3c7e6b opt 2024-08-02 10:49:30 +00:00
idranme
3f5ca8ebfa chore 2024-08-02 10:31:37 +00:00
idranme
6e8389e833 chore 2024-08-02 10:26:18 +00:00
idranme
71aedca4c6 feat: the name attribute of the at message segment 2024-08-02 10:23:48 +00:00
Alen
6410689549 BUG修复
尝试修复设精事件shortId和senderId
2024-08-01 21:56:44 +08:00
linyuchen
6d0e2269cc Merge pull request #304 from cnxysoft/dev
功能更新
2024-07-28 14:52:58 +08:00
linyuchen
2e28fc678c Merge branch 'dev' into dev 2024-07-28 14:52:17 +08:00
linyuchen
8204f4407f Merge pull request #300 from super1207/dev
Merge branch 'dev' of https://github.com/LLOneBot/LLOneBot into dev
2024-07-26 09:57:37 +08:00
Alen
9f1d4c4db2 功能修改
修改群管变更事件获取渠道,让所有群角色都能收到群管变更通知
2024-07-25 17:25:40 +08:00
Alen
8ba47635d3 功能更新
1.增加设精事件上报(目前上报的shortId经常出错,实际消息体却是正确的,待解决)
2.增加设精/取消设精api接口
3.poke事件增加raw信息上报
2024-07-25 01:02:48 +08:00
Alen
5fa2427c51 修改poke事件
新增poke事件支持上传raw信息
2024-07-24 19:04:07 +08:00
Alen
aa8739d016 Merge remote-tracking branch 'upstream/main' into dev 2024-07-24 11:48:55 +08:00
super1207
79f0329da7 Merge branch 'dev' of https://github.com/LLOneBot/LLOneBot into dev 2024-07-20 18:01:30 +08:00
super1207
7a33a36f44 add get_event api 2024-07-20 17:58:00 +08:00
linyuchen
808424d08e Merge branch 'main' into dev 2024-07-20 17:08:59 +08:00
linyuchen
d0967785de chore: v3.27.3 2024-07-20 16:58:03 +08:00
linyuchen
eccabb8189 Merge pull request #299 from Natsukage/main
fix: skip problematic name-value pairs in encodeCQCode to prevent undefined errors
2024-07-20 15:25:27 +08:00
夏影
c9374ff515 fix: skip problematic name-value pairs in encodeCQCode to prevent undefined errors
Added logic to skip name-value pairs in encodeCQCode when value cannot be converted to string, preventing errors caused by undefined values. This ensures the function can handle such cases gracefully and continue processing other valid data.
2024-07-20 00:49:34 +08:00
Alen
92c4889924 Merge remote-tracking branch 'upstream/main' 2024-07-16 23:19:32 +08:00
linyuchen
f9454039a1 fix: old poke event 2024-07-16 21:52:15 +08:00
linyuchen
bc4511e175 chore: v3.27.2 2024-07-16 21:43:50 +08:00
linyuchen
f191103f99 Merge pull request #294 from cnxysoft/dev
修复戳一戳
2024-07-16 21:38:17 +08:00
linyuchen
408463f63b Merge branch 'dev' into dev 2024-07-16 21:21:50 +08:00
Alen
fb96c4272e 修复戳一戳
取缔FriendAddEvent,并入Private Event处理
2024-07-16 21:01:19 +08:00
Alen
c6b302d5a8 修复好友戳一戳
取缔FriendAddEvent,并入Private Event处理
2024-07-16 20:27:44 +08:00
19 changed files with 387 additions and 94 deletions

View File

@@ -1,10 +1,10 @@
{
"manifest_version": 4,
"type": "extension",
"name": "LLOneBot v3.27.1",
"name": "LLOneBot v3.27.4",
"slug": "LLOneBot",
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发",
"version": "3.27.1",
"version": "3.27.4",
"icon": "./icon.jpg",
"authors": [
{

View File

@@ -191,12 +191,20 @@ function onLoad() {
postOb11Event(groupEvent)
}
})
OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => {
if (friendAddEvent) {
// log("post friend add event", friendAddEvent);
postOb11Event(friendAddEvent)
OB11Constructor.PrivateEvent(message).then((privateEvent) => {
log(message)
if (privateEvent) {
// log("post private event", privateEvent);
postOb11Event(privateEvent)
}
})
// OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => {
// log(message)
// if (friendAddEvent) {
// // log("post friend add event", friendAddEvent);
// postOb11Event(friendAddEvent)
// }
// })
}
}
@@ -215,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)
})
@@ -310,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)

View File

@@ -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);
}
}

View File

@@ -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<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
export let sentMessages: Record<string, RawMessage> = {} // 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);
}
}

View File

@@ -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<string, (apiReturn: any) => 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)
}

View File

@@ -415,3 +415,9 @@ export interface RawMessage {
multiForwardMsgElement: MultiForwardMsgElement
}[]
}
export interface Peer {
chatType: ChatType;
peerUid: string; // 如果是群聊uid为群号私聊uid就是加密的字符串
guildId?: string;
}

View File

@@ -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<Payload, any> {
actionName = ActionName.GoCQHTTP_DelEssenceMsg;
protected async _handle(payload: Payload): Promise<any> {
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
);
}
}

View File

@@ -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<Payload, any> {
actionName = ActionName.GoCQHTTP_SetEssenceMsg;
protected async _handle(payload: Payload): Promise<any> {
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
);
}
}

View File

@@ -50,6 +50,10 @@ 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(),
@@ -59,6 +63,7 @@ export const actionHandlers = [
new GetGroupAddRequest(),
new SetQQAvatar(),
new GetFriendWithCategory(),
new GetEvent(),
// onebot11
new SendLike(),
new GetMsg(),
@@ -106,7 +111,9 @@ export const actionHandlers = [
new GoCQHTTPUploadPrivateFile(),
new GoCQHTTPGetGroupMsgHistory(),
new GoCQHTTGetForwardMsgAction(),
new GoCQHTTHandleQuickOperation()
new GoCQHTTHandleQuickOperation(),
new GoCQHTTPSetEssenceMsg(),
new GoCQHTTPDelEssenceMsg()
]
function initActionMap() {

View File

@@ -0,0 +1,23 @@
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
import { getHttpEvent } from '../../server/event-for-http'
import { PostEventType } from '../../server/post-ob11-event'
// import { log } from "../../../common/utils";
interface Payload {
key: string
timeout: number
}
export default class GetEvent extends BaseAction<Payload, PostEventType[]> {
actionName = ActionName.GetEvent
protected async _handle(payload: Payload): Promise<PostEventType[]> {
let key = ''
if (payload.key) {
key = payload.key;
}
let timeout = parseInt(payload.timeout?.toString()) || 0;
let evts = await getHttpEvent(key,timeout);
return evts;
}
}

View File

@@ -22,6 +22,7 @@ export enum ActionName {
Debug = 'llonebot_debug',
GetFile = 'get_file',
GetFriendsWithCategory = 'get_friends_with_category',
GetEvent = 'get_event',
// onebot 11
SendLike = 'send_like',
GetLoginInfo = 'get_login_info',
@@ -70,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',
}

View File

@@ -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'
@@ -47,7 +49,9 @@ import { mFaceCache } from '../ntqqapi/constructor'
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
import { OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent';
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent';
let lastRKeyUpdateTime = 0
@@ -108,33 +112,40 @@ export class OB11Constructor {
}
for (let element of msg.elements) {
let message_data: OB11MessageData | any = {
data: {},
type: 'unknown',
let message_data: OB11MessageData = {
data: {} as any,
type: 'unknown' as any,
}
if (element.textElement && element.textElement?.atType !== AtType.notAt) {
message_data['type'] = OB11MessageDataType.at
let qq: string
let name: string | undefined
if (element.textElement.atType == AtType.atAll) {
// message_data["data"]["mention"] = "all"
message_data['data']['qq'] = 'all'
qq = 'all'
}
else {
let atUid = element.textElement.atNtUid
const { atNtUid, content } = element.textElement
let atQQ = element.textElement.atUid
if (!atQQ || atQQ === '0') {
const atMember = await getGroupMember(msg.peerUin, atUid)
const atMember = await getGroupMember(msg.peerUin, atNtUid)
if (atMember) {
atQQ = atMember.uin
}
}
if (atQQ) {
// message_data["data"]["mention"] = atQQ
message_data['data']['qq'] = atQQ
qq = atQQ
name = content.replace('@', '')
}
}
message_data = {
type: OB11MessageDataType.at,
data: {
qq,
name
}
}
}
else if (element.textElement) {
message_data['type'] = 'text'
message_data['type'] = OB11MessageDataType.text
let text = element.textElement.content
if (!text.trim()) {
continue
@@ -142,7 +153,7 @@ export class OB11Constructor {
message_data['data']['text'] = text
}
else if (element.replyElement) {
message_data['type'] = 'reply'
message_data['type'] = OB11MessageDataType.reply
// log("收到回复消息", element.replyElement.replayMsgSeq)
try {
const replyMsg = await dbUtil.getMsgBySeqId(element.replyElement.replayMsgSeq)
@@ -158,7 +169,7 @@ export class OB11Constructor {
}
}
else if (element.picElement) {
message_data['type'] = 'image'
message_data['type'] = OB11MessageDataType.image
// message_data["data"]["file"] = element.picElement.sourcePath
let fileName = element.picElement.fileName
const sourcePath = element.picElement.sourcePath
@@ -203,9 +214,9 @@ export class OB11Constructor {
message_data['data']['file_size'] = videoOrFileElement.fileSize
if (element.videoElement) {
message_data['data']['url'] = await NTQQFileApi.getVideoUrl({
chatType: msg.chatType,
peerUid: msg.peerUid,
}, msg.msgId, element.elementId,
chatType: msg.chatType,
peerUid: msg.peerUid,
}, msg.msgId, element.elementId,
)
}
dbUtil
@@ -295,7 +306,7 @@ export class OB11Constructor {
message_data['type'] = OB11MessageDataType.forward
message_data['data']['id'] = msg.msgId
}
if (message_data.type !== 'unknown' && message_data.data) {
if ((message_data.type as string) !== 'unknown' && message_data.data) {
const cqCode = encodeCQCode(message_data)
if (messagePostFormat === 'string') {
(resMsg.message as string) += cqCode
@@ -309,6 +320,35 @@ export class OB11Constructor {
return resMsg
}
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent> {
if (msg.chatType !== ChatType.friend) {
return;
}
for (const element of msg.elements) {
if (element.grayTipElement) {
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr);
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
//判断业务类型
//Poke事件
const pokedetail: any[] = json.items;
//筛选item带有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
}
}
}
// 好友增加事件
if (msg.msgType === 5 && msg.subMsgType === 12) {
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin))
return event
}
}
static async GroupEvent(msg: RawMessage): Promise<OB11GroupNoticeEvent> {
if (msg.chatType !== ChatType.group) {
return
@@ -496,36 +536,48 @@ 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!
};
let msgList = (await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true)).msgList;
const origMsg = await dbUtil.getMsgByLongId(msgList[0].msgId);
const postMsg = await dbUtil.getMsgBySeqId(origMsg.msgSeq) ?? origMsg;
// 如果 senderUin 为 0可能是 历史消息 或 自身消息
if (msgList[0].senderUin === '0') {
msgList[0].senderUin = postMsg?.senderUin ?? selfInfo.uin;
}
return new OB11GroupEssenceEvent(parseInt(msg.peerUid), postMsg.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)
}
}
}
}
}
static async FriendAddEvent(msg: RawMessage): Promise<OB11FriendAddNoticeEvent | undefined> {
if (msg.chatType !== ChatType.friend) {
return
}
if (msg.msgType === 5 && msg.subMsgType === 12) {
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin))
return event
}
return
}
static async RecallEvent(
msg: RawMessage,
): Promise<OB11FriendRecallNoticeEvent | OB11GroupRecallNoticeEvent | undefined> {

View File

@@ -50,7 +50,6 @@ export function encodeCQCode(data: OB11MessageData) {
}
const CQCodeEscape = (text: string) => {
text = text.toString()
return text.replace(/\&/g, '&amp;').replace(/\[/g, '&#91;').replace(/\]/g, '&#93;').replace(/,/g, '&#44;')
}
@@ -61,7 +60,15 @@ export function encodeCQCode(data: OB11MessageData) {
let result = '[CQ:' + data.type
for (const name in data.data) {
const value = data.data[name]
result += `,${name}=${CQCodeEscape(value)}`
if (value === undefined) {
continue
}
try {
const text = value.toString()
result += `,${name}=${CQCodeEscape(text)}`
} catch (error) {
// If it can't be converted, skip this name-value pair
}
}
result += ']'
return result

View File

@@ -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;
}
}

View File

@@ -5,26 +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 {
sender_id: number
constructor(user_id: number) {
super()
this.user_id = user_id
this.sender_id = user_id
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
}
}

View File

@@ -0,0 +1,68 @@
import { PostEventType } from "./post-ob11-event"
interface HttpEventType {
seq: number
event: PostEventType
}
interface HttpUserType {
lastAccessTime: number
userSeq: number
}
let curentSeq:number = 0;
let eventList:HttpEventType[] = [];
let httpUser:Record<string,HttpUserType> = {};
export function postHttpEvent(event: PostEventType) {
curentSeq += 1;
eventList.push({
seq: curentSeq,
event: event
});
while(eventList.length > 100) {
eventList.shift();
}
}
export async function getHttpEvent(userKey:string,timeout = 0) {
let toRetEvent = [];
// 清除过时的user5分钟没访问过的user将被删除
let now = Date.now();
for(let key in httpUser) {
let user = httpUser[key];
if(now - user.lastAccessTime > 1000 * 60 * 5) {
delete httpUser[key];
}
}
// 增加新的user
if(!httpUser[userKey] ) {
httpUser[userKey] = {
lastAccessTime: now,
userSeq: curentSeq
}
}
let user = httpUser[userKey];
// 等待数据到来,暂时先这么写吧......
while(curentSeq == user.userSeq && Date.now() - now < timeout) {
await new Promise( resolve => setTimeout(resolve, 10) );
}
// 取数据
for(let i = 0; i < eventList.length; i++) {
let evt = eventList[i];
if(evt.seq > user.userSeq) {
toRetEvent.push(evt.event);
}
}
// 更新user数据
user.lastAccessTime = Date.now();
user.userSeq = curentSeq;
return toRetEvent;
}

View File

@@ -8,6 +8,7 @@ import { log } from '@/common/utils'
import { getConfigUtil } from '@/common/config'
import crypto from 'crypto'
import { handleQuickOperation, QuickOperationEvent } from '../action/quick-operation'
import { postHttpEvent } from './event-for-http'
export type PostEventType = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent
@@ -78,4 +79,9 @@ export function postOb11Event(msg: PostEventType, reportSelf = false, postWs = t
if (postWs) {
postWsEvent(msg)
}
if(!(msg.post_type == 'meta_event' && (msg as OB11BaseMetaEvent).meta_event_type == 'heartbeat')) {
// 不上报心跳
postHttpEvent(msg)
}
}

View File

@@ -195,6 +195,7 @@ export interface OB11MessageAt {
type: OB11MessageDataType.at
data: {
qq: string | 'all'
name?: string
}
}
@@ -241,6 +242,20 @@ export interface OB11MessageJson {
data: { data: string /* , config: { token: string } */ }
}
export interface OB11MessageMarkdown {
type: OB11MessageDataType.markdown
data: {
data: string
}
}
export interface OB11MessageForward {
type: OB11MessageDataType.forward
data: {
id: string
}
}
export type OB11MessageData =
| OB11MessageText
| OB11MessageFace
@@ -258,6 +273,8 @@ export type OB11MessageData =
| OB11MessagePoke
| OB11MessageDice
| OB11MessageRPS
| OB11MessageMarkdown
| OB11MessageForward
export interface OB11PostSendMsg {
message_type?: 'private' | 'group'

View File

@@ -1 +1 @@
export const version = '3.27.1'
export const version = '3.27.4'