From 9b3916307a0a35bf64a724e0cebd1b8b70b1ec80 Mon Sep 17 00:00:00 2001 From: linyuchen Date: Sat, 11 May 2024 14:52:59 +0800 Subject: [PATCH] fix: All images are the first image in single msg fix: remote rkey --- electron.vite.config.ts | 4 +- manifest.json | 12 ++-- src/ntqqapi/api/file.ts | 108 ++++-------------------------------- src/ntqqapi/api/rkey.ts | 59 ++++++++++++++++++++ src/onebot11/constructor.ts | 71 ++++++++++++++++-------- src/version.ts | 2 +- 6 files changed, 129 insertions(+), 127 deletions(-) create mode 100644 src/ntqqapi/api/rkey.ts diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 755888e..a469511 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -46,8 +46,8 @@ let config = { { src: './manifest.json', dest: 'dist' }, { src: './icon.jpg', dest: 'dist' }, { src: './src/ntqqapi/native/crychic/crychic-win32-x64.node', dest: 'dist/main/' }, - { src: './src/ntqqapi/native/moehook/MoeHoo-win32-x64.node', dest: 'dist/main/' }, - { src: './src/ntqqapi/native/moehook/MoeHoo-linux-x64.node', dest: 'dist/main/' }, + // { src: './src/ntqqapi/native/moehook/MoeHoo-win32-x64.node', dest: 'dist/main/' }, + // { src: './src/ntqqapi/native/moehook/MoeHoo-linux-x64.node', dest: 'dist/main/' }, ], }), ], diff --git a/manifest.json b/manifest.json index bbf3bc5..7ae2ecd 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "manifest_version": 4, "type": "extension", - "name": "LLOneBot v3.24.2", + "name": "LLOneBot v3.24.3", "slug": "LLOneBot", "description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新", - "version": "3.24.2", + "version": "3.24.3", "icon": "./icon.jpg", "authors": [ { @@ -20,10 +20,14 @@ "name": "LLOneBot.zip" } }, - "platform": ["win32", "linux", "darwin"], + "platform": [ + "win32", + "linux", + "darwin" + ], "injects": { "renderer": "./renderer/index.js", "main": "./main/main.cjs", "preload": "./preload/preload.cjs" } -} +} \ No newline at end of file diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index f0a69f5..c956757 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -9,22 +9,14 @@ import { ChatType, ElementType, IMAGE_HTTP_HOST, - IMAGE_HTTP_HOST_NT, + IMAGE_HTTP_HOST_NT, PicElement, RawMessage, } from '../types' import path from 'path' import fs from 'fs' import { ReceiveCmdS } from '../hook' import { log } from '@/common/utils' -import https from 'https' -import { sleep } from '@/common/utils' -import { hookApi } from '../native/moehook/hook' - -let privateImageRKey = '' -let groupImageRKey = '' -let lastGetPrivateRKeyTime = 0 -let lastGetGroupRKeyTime = 0 -const rkeyExpireTime = 1000 * 60 * 30 +import { rkeyManager } from '@/ntqqapi/api/rkey' export class NTQQFileApi { static async getFileType(filePath: string) { @@ -161,16 +153,12 @@ export class NTQQFileApi { }) } - static async getImageUrl(msg: RawMessage) { - const isPrivateImage = msg.chatType !== ChatType.group - const msgElement = msg.elements.find((e) => !!e.picElement) - if (!msgElement) { - return '' - } - const url = msgElement.picElement.originImageUrl // 没有域名 - const md5HexStr = msgElement.picElement.md5HexStr - const fileMd5 = msgElement.picElement.md5HexStr - const fileUuid = msgElement.picElement.fileUuid + static async getImageUrl(picElement: PicElement, chatType: ChatType) { + const isPrivateImage = chatType !== ChatType.group + const url = picElement.originImageUrl // 没有域名 + const md5HexStr = picElement.md5HexStr + const fileMd5 = picElement.md5HexStr + const fileUuid = picElement.fileUuid if (url) { if (url.startsWith('/download')) { // console.log('rkey', rkey); @@ -178,81 +166,9 @@ export class NTQQFileApi { return IMAGE_HTTP_HOST_NT + url } - if (!hookApi.isAvailable()) { - log('hookApi is not available') - return '' - } - - const saveRKey = (rkey: string) => { - if (isPrivateImage) { - privateImageRKey = rkey - lastGetPrivateRKeyTime = Date.now() - } else { - groupImageRKey = rkey - lastGetGroupRKeyTime = Date.now() - } - } - - const refreshRKey = async () => { - log('获取图片rkey...') - NTQQFileApi.downloadMedia( - msg.msgId, - msg.chatType, - msg.peerUid, - msgElement.elementId, - '', - msgElement.picElement.sourcePath, - false, - ) - .then() - .catch(() => {}) - await sleep(1000) - const _rkey = hookApi.getRKey() - if (_rkey) { - const imageUrl = IMAGE_HTTP_HOST_NT + url + _rkey - // 验证_rkey是否有效 - try { - await new Promise((res, rej) => { - https - .get(imageUrl, (response) => { - if (response.statusCode !== 200) { - rej('图片rkey获取失败') - } else { - res(response) - } - }) - .on('error', (e) => { - rej(e) - }) - }) - log('图片rkey获取成功', _rkey) - saveRKey(_rkey) - return _rkey - } catch (e) { - log('图片rkey有误', imageUrl) - } - } - } - - const existsRKey = isPrivateImage ? privateImageRKey : groupImageRKey - const lastGetRKeyTime = isPrivateImage ? lastGetPrivateRKeyTime : lastGetGroupRKeyTime - if (Date.now() - lastGetRKeyTime > rkeyExpireTime) { - // rkey过期 - const newRKey = await refreshRKey() - if (newRKey) { - return IMAGE_HTTP_HOST_NT + url + `${newRKey}` - } else { - log('图片rkey获取失败', url) - if (existsRKey) { - return IMAGE_HTTP_HOST_NT + url + `${existsRKey}` - } - return '' - } - } - // 使用未过期的rkey - if (existsRKey) { - return IMAGE_HTTP_HOST_NT + url + `${existsRKey}` - } + const rkeyData = await rkeyManager.getRkey(); + const existsRKey = isPrivateImage ? rkeyData.private_rkey : rkeyData.group_rkey; + return IMAGE_HTTP_HOST_NT + url + `${existsRKey}` } else { // 老的图片url,不需要rkey return IMAGE_HTTP_HOST + url @@ -261,7 +177,7 @@ export class NTQQFileApi { // 没有url,需要自己拼接 return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0` } - log('图片url获取失败', msg) + log('图片url获取失败', picElement) return '' } } diff --git a/src/ntqqapi/api/rkey.ts b/src/ntqqapi/api/rkey.ts new file mode 100644 index 0000000..25ebbaf --- /dev/null +++ b/src/ntqqapi/api/rkey.ts @@ -0,0 +1,59 @@ +//远端rkey获取 + +import { log } from '@/common/utils' + +interface ServerRkeyData{ + group_rkey: string; + private_rkey: string; + expired_time: number; +} + +class RkeyManager { + serverUrl: string = ''; + private rkeyData: ServerRkeyData = { + group_rkey: '', + private_rkey: '', + expired_time: 0 + }; + constructor(serverUrl: string) { + this.serverUrl = serverUrl; + } + async getRkey(){ + if (this.isExpired()) { + try { + await this.refreshRkey(); + } catch (e) { + log('获取rkey失败', e); + } + } + return this.rkeyData; + } + + isExpired(): boolean { + const now = new Date().getTime() / 1000; + // console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`); + return now > this.rkeyData.expired_time; + } + async refreshRkey(): Promise { + //刷新rkey + this.rkeyData = await this.fetchServerRkey(); + } + async fetchServerRkey(){ + return new Promise((resolve, reject) => { + fetch(this.serverUrl) + .then(response => { + if (!response.ok) { + return reject(response.statusText); // 请求失败,返回错误信息 + } + return response.json(); // 解析 JSON 格式的响应体 + }) + .then(data => { + resolve(data); + }) + .catch(error => { + reject(error); + }); + }); + } +} +export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey'); diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index 7eb28a5..6d9e01d 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -87,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) { @@ -111,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') { @@ -125,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 { @@ -140,20 +145,22 @@ 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 // message_data["data"]["path"] = element.picElement.sourcePath // let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64" - message_data['data']['url'] = await NTQQFileApi.getImageUrl(msg) + message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement, msg.chatType); // message_data["data"]["file_id"] = element.picElement.fileUuid message_data['data']['file_size'] = element.picElement.fileSize dbUtil @@ -175,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 @@ -204,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 @@ -224,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 @@ -253,10 +267,12 @@ export class OB11Constructor { 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) { + } + 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 } @@ -264,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 } @@ -313,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 @@ -324,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 @@ -341,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() @@ -361,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, @@ -426,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) /* { @@ -495,7 +517,8 @@ export class OB11Constructor { parseInt(operator.uin), msg.msgShortId, ) - } else { + } + else { return new OB11FriendRecallNoticeEvent(parseInt(msg.senderUin), msg.msgShortId) } } diff --git a/src/version.ts b/src/version.ts index 0947d34..c6ec41e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '3.24.2' +export const version = '3.24.3'