Compare commits

..

10 Commits

Author SHA1 Message Date
linyuchen
1da086ce0a chore: v3.24.2 2024-05-05 20:20:30 +08:00
linyuchen
e9d43a9449 fix: http download filename special character 2024-05-05 20:06:07 +08:00
linyuchen
ce31052661 refactor: OB11Message add message_seq filed 2024-05-05 19:42:48 +08:00
linyuchen
3fd9b0a183 fix: 表情回应兼容int类型的emoji_id 2024-05-05 13:07:07 +08:00
linyuchen
7e1dee8e07 fix: msg db cache missing shortId 2024-05-04 23:35:19 +08:00
linyuchen
f2854fdf00 fix: report self recall twice 2024-05-04 20:30:39 +08:00
linyuchen
1fad95a55b chore: Version 3.24.1 2024-05-04 11:34:41 +08:00
linyuchen
5342e1521c Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/ntqqapi/external/moehook/MoeHoo-linux-x64.node
2024-05-03 21:26:31 +08:00
student_2333
3c532526df chore: sync external files 2024-05-01 15:25:49 +08:00
student_2333
05c6cae86f fix: reference before define 2024-05-01 11:10:42 +08:00
11 changed files with 96 additions and 56 deletions

View File

@@ -1,10 +1,10 @@
{
"manifest_version": 4,
"type": "extension",
"name": "LLOneBot v3.24.0",
"name": "LLOneBot v3.24.1",
"slug": "LLOneBot",
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新",
"version": "3.24.0",
"version": "3.24.1",
"icon": "./icon.jpg",
"authors": [
{

View File

@@ -49,7 +49,7 @@ class DBUtil {
setTimeout(initDB, 300)
}
}
initDB()
setTimeout(initDB)
}).then()
const expiredMilliSecond = 1000 * 60 * 60
@@ -154,12 +154,12 @@ class DBUtil {
this.updateMsg(msg).then()
return existMsg.msgShortId
}
this.addCache(msg)
const shortMsgId = await this.genMsgShortId()
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq
msg.msgShortId = shortMsgId
this.addCache(msg)
// log("新增消息记录", msg.msgId)
this.db.put(shortIdKey, msg.msgId).then().catch()
this.db.put(longIdKey, JSON.stringify(msg)).then().catch()

View File

@@ -176,6 +176,7 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
// res.ext = pathInfo.ext
}
}
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_')
res.fileName = fileName
filePath = path.join(TEMP_DIR, uuidv4() + fileName)
fs.writeFileSync(filePath, buffer)

View File

@@ -198,6 +198,7 @@ function onLoad() {
postOB11Event(friendAddEvent)
}
})
}
}
@@ -224,39 +225,28 @@ function onLoad() {
log('report message error: ', e.stack.toString())
}
})
const recallMsgIds: string[] = []; // 避免重复上报
registerReceiveHook<{ msgList: Array<RawMessage> }>([ReceiveCmdS.UPDATE_MSG], async (payload) => {
for (const message of payload.msgList) {
// log("message update", message)
log("message update", message.msgId, message)
if (message.recallTime != '0') {
//todo: 这个判断方法不太好,应该使用灰色消息元素来判断
// 撤回消息上报
if (recallMsgIds.includes(message.msgId)) {
continue
}
recallMsgIds.push(message.msgId);
const oriMessage = await dbUtil.getMsgByLongId(message.msgId)
if (!oriMessage) {
continue
}
oriMessage.recallTime = message.recallTime
dbUtil.updateMsg(oriMessage).then()
if (message.chatType == ChatType.friend) {
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
parseInt(message.senderUin),
oriMessage.msgShortId,
)
postOB11Event(friendRecallEvent)
} else if (message.chatType == ChatType.group) {
let operatorId = message.senderUin
for (const element of message.elements) {
const operatorUid = element.grayTipElement?.revokeElement.operatorUid
const operator = await getGroupMember(message.peerUin, operatorUid)
operatorId = operator.uin
message.msgShortId = oriMessage.msgShortId;
OB11Constructor.RecallEvent(message).then((recallEvent) => {
if (recallEvent) {
log("post recall event", recallEvent);
postOB11Event(recallEvent)
}
const groupRecallEvent = new OB11GroupRecallNoticeEvent(
parseInt(message.peerUin),
parseInt(message.senderUin),
parseInt(operatorId),
oriMessage.msgShortId,
)
postOB11Event(groupRecallEvent)
}
})
// 不让入库覆盖原来消息,不然就获取不到撤回的消息内容了
continue
}

View File

@@ -225,7 +225,8 @@ export class NTQQFileApi {
// 老的图片url不需要rkey
return IMAGE_HTTP_HOST + url
}
} else if (fileMd5 || md5HexStr) {
}
else if (fileMd5 || md5HexStr) {
// 没有url需要自己拼接
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0`
}

View File

@@ -20,6 +20,7 @@ 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
emojiId = emojiId.toString();
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.EMOJI_LIKE,
args: [

View File

@@ -201,6 +201,7 @@ export interface PicElement {
}
export enum GrayTipElementSubType {
RECALL = 1,
INVITE_NEW_MEMBER = 12,
MEMBER_NEW_TITLE = 17,
}
@@ -213,6 +214,8 @@ export interface GrayTipElement {
operatorNick: string
operatorRemark: string
operatorMemRemark?: string
origMsgSenderUid?: string
isSelfOperate?: boolean
wording: string // 自定义的撤回提示语
}
aioOpGrayTipElement: TipAioOpGrayTipElement

View File

@@ -46,6 +46,8 @@ import { NTQQGroupApi } from '../ntqqapi/api'
import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent'
import { mFaceCache } from '../ntqqapi/constructor'
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
let lastRKeyUpdateTime = 0
@@ -63,6 +65,7 @@ export class OB11Constructor {
time: parseInt(msg.msgTime) || Date.now(),
message_id: msg.msgShortId,
real_id: msg.msgShortId,
message_seq: msg.msgShortId,
message_type: msg.chatType == ChatType.group ? 'group' : 'private',
sender: {
user_id: parseInt(msg.senderUin),
@@ -84,13 +87,15 @@ export class OB11Constructor {
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role)
resMsg.sender.nickname = member.nick
}
} else if (msg.chatType == ChatType.friend) {
}
else if (msg.chatType == ChatType.friend) {
resMsg.sub_type = 'friend'
const friend = await getFriend(msg.senderUin)
if (friend) {
resMsg.sender.nickname = friend.nick
}
} else if (msg.chatType == ChatType.temp) {
}
else if (msg.chatType == ChatType.temp) {
resMsg.sub_type = 'group'
const tempGroupCode = tempGroupCodeMap[msg.peerUin]
if (tempGroupCode) {
@@ -108,7 +113,8 @@ export class OB11Constructor {
if (element.textElement.atType == AtType.atAll) {
// message_data["data"]["mention"] = "all"
message_data['data']['qq'] = 'all'
} else {
}
else {
let atUid = element.textElement.atNtUid
let atQQ = element.textElement.atUid
if (!atQQ || atQQ === '0') {
@@ -122,14 +128,16 @@ export class OB11Constructor {
message_data['data']['qq'] = atQQ
}
}
} else if (element.textElement) {
}
else if (element.textElement) {
message_data['type'] = 'text'
let text = element.textElement.content
if (!text.trim()) {
continue
}
message_data['data']['text'] = text
} else if (element.replyElement) {
}
else if (element.replyElement) {
message_data['type'] = 'reply'
// log("收到回复消息", element.replyElement.replayMsgSeq)
try {
@@ -137,13 +145,15 @@ export class OB11Constructor {
// log("找到回复消息", replyMsg.msgShortId, replyMsg.msgId)
if (replyMsg) {
message_data['data']['id'] = replyMsg.msgShortId.toString()
} else {
}
else {
continue
}
} catch (e) {
log('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq)
}
} else if (element.picElement) {
}
else if (element.picElement) {
message_data['type'] = 'image'
// message_data["data"]["file"] = element.picElement.sourcePath
message_data['data']['file'] = element.picElement.fileName
@@ -172,7 +182,8 @@ export class OB11Constructor {
})
.then()
// 不在自动下载图片
} else if (element.videoElement || element.fileElement) {
}
else if (element.videoElement || element.fileElement) {
const videoOrFileElement = element.videoElement || element.fileElement
const ob11MessageDataType = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file
message_data['type'] = ob11MessageDataType
@@ -201,7 +212,8 @@ export class OB11Constructor {
})
.then()
// 怎么拿到url呢
} else if (element.pttElement) {
}
else if (element.pttElement) {
message_data['type'] = OB11MessageDataType.voice
message_data['data']['file'] = element.pttElement.fileName
message_data['data']['path'] = element.pttElement.filePath
@@ -221,22 +233,27 @@ export class OB11Constructor {
// }).catch(err => {
// console.log("语音转文字失败", err);
// })
} else if (element.arkElement) {
}
else if (element.arkElement) {
message_data['type'] = OB11MessageDataType.json
message_data['data']['data'] = element.arkElement.bytesData
} else if (element.faceElement) {
}
else if (element.faceElement) {
const faceId = element.faceElement.faceIndex
if (faceId === FaceIndex.dice) {
message_data['type'] = OB11MessageDataType.dice
message_data['data']['result'] = element.faceElement.resultId
} else if (faceId === FaceIndex.RPS) {
}
else if (faceId === FaceIndex.RPS) {
message_data['type'] = OB11MessageDataType.RPS
message_data['data']['result'] = element.faceElement.resultId
} else {
}
else {
message_data['type'] = OB11MessageDataType.face
message_data['data']['id'] = element.faceElement.faceIndex.toString()
}
} else if (element.marketFaceElement) {
}
else if (element.marketFaceElement) {
message_data['type'] = OB11MessageDataType.mface
message_data['data']['summary'] = element.marketFaceElement.faceName
const md5 = element.marketFaceElement.emojiId
@@ -249,11 +266,13 @@ export class OB11Constructor {
message_data['data']['emoji_id'] = element.marketFaceElement.emojiId
message_data['data']['emoji_package_id'] = String(element.marketFaceElement.emojiPackageId)
message_data['data']['key'] = element.marketFaceElement.key
mFaceCache.set(md5, element.marketFaceElement.faceName);
} else if (element.markdownElement) {
mFaceCache.set(md5, element.marketFaceElement.faceName)
}
else if (element.markdownElement) {
message_data['type'] = OB11MessageDataType.markdown
message_data['data']['data'] = element.markdownElement.content
} else if (element.multiForwardMsgElement) {
}
else if (element.multiForwardMsgElement) {
message_data['type'] = OB11MessageDataType.forward
message_data['data']['id'] = msg.msgId
}
@@ -261,7 +280,8 @@ export class OB11Constructor {
const cqCode = encodeCQCode(message_data)
if (messagePostFormat === 'string') {
;(resMsg.message as string) += cqCode
} else (resMsg.message as OB11MessageData[]).push(message_data)
}
else (resMsg.message as OB11MessageData[]).push(message_data)
resMsg.raw_message += cqCode
}
@@ -310,7 +330,8 @@ export class OB11Constructor {
// log("构造群增加事件", event)
return event
}
} else if (groupElement.type === TipGroupElementType.ban) {
}
else if (groupElement.type === TipGroupElementType.ban) {
log('收到群群员禁言提示', groupElement)
const memberUid = groupElement.shutUp.member.uid
const adminUid = groupElement.shutUp.admin.uid
@@ -321,7 +342,8 @@ export class OB11Constructor {
memberUin =
(await getGroupMember(msg.peerUid, memberUid))?.uin ||
(await NTQQUserApi.getUserDetailInfo(memberUid))?.uin
} else {
}
else {
memberUin = '0' // 0表示全员禁言
if (duration > 0) {
duration = -1
@@ -338,7 +360,8 @@ export class OB11Constructor {
sub_type,
)
}
} else if (groupElement.type == TipGroupElementType.kicked) {
}
else if (groupElement.type == TipGroupElementType.kicked) {
log(`收到我被踢出或退群提示, 群${msg.peerUid}`, groupElement)
deleteGroup(msg.peerUid)
NTQQGroupApi.quitGroup(msg.peerUid).then()
@@ -358,7 +381,8 @@ export class OB11Constructor {
return new OB11GroupDecreaseEvent(parseInt(msg.peerUid), parseInt(selfInfo.uin), 0, 'leave')
}
}
} else if (element.fileElement) {
}
else if (element.fileElement) {
return new OB11GroupUploadNoticeEvent(parseInt(msg.peerUid), parseInt(msg.senderUin), {
id: element.fileElement.fileUuid,
name: element.fileElement.fileName,
@@ -423,7 +447,8 @@ export class OB11Constructor {
return new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(invitee), parseInt(inviter), 'invite')
}
}
} else if (grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
}
else if (grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr)
/*
{
@@ -463,14 +488,32 @@ export class OB11Constructor {
static async FriendAddEvent(msg: RawMessage): Promise<OB11FriendAddNoticeEvent | undefined> {
if (msg.chatType !== ChatType.friend) {
return;
return
}
if (msg.msgType === 5 && msg.subMsgType === 12) {
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin));
return event;
const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin))
return event
}
return;
return
}
static async RecallEvent(msg: RawMessage): Promise<OB11FriendRecallNoticeEvent | OB11GroupRecallNoticeEvent | undefined>{
let msgElement = msg.elements.find((element) => element.grayTipElement?.subElementType === GrayTipElementSubType.RECALL);
if (!msgElement) {
return
}
const isGroup = msg.chatType === ChatType.group;
const revokeElement = msgElement.grayTipElement.revokeElement;
if (isGroup){
const operator = await getGroupMember(msg.peerUid, revokeElement.operatorUid);
const sender = await getGroupMember(msg.peerUid, revokeElement.origMsgSenderUid);
return new OB11GroupRecallNoticeEvent(parseInt(msg.peerUid), parseInt(sender.uin), parseInt(operator.uin), msg.msgShortId)
}
else{
return new OB11FriendRecallNoticeEvent(parseInt(msg.senderUin), msg.msgShortId)
}
}
static friend(friend: User): OB11User {
return {
user_id: parseInt(friend.uin),

View File

@@ -75,6 +75,7 @@ export interface OB11Message {
self_id?: number
time: number
message_id: number
message_seq: number // go-cqhttp字段实际上是message_id
real_id: number
user_id: number
group_id?: number

View File

@@ -1 +1 @@
export const version = '3.24.0'
export const version = '3.24.2'