mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
fix: All images are the first image in single msg
fix: remote rkey
This commit is contained in:
parent
fdf96b479c
commit
9b3916307a
@ -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/' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -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 ''
|
||||
}
|
||||
}
|
||||
|
59
src/ntqqapi/api/rkey.ts
Normal file
59
src/ntqqapi/api/rkey.ts
Normal file
@ -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<any> {
|
||||
//刷新rkey
|
||||
this.rkeyData = await this.fetchServerRkey();
|
||||
}
|
||||
async fetchServerRkey(){
|
||||
return new Promise<ServerRkeyData>((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');
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
export const version = '3.24.2'
|
||||
export const version = '3.24.3'
|
||||
|
Loading…
x
Reference in New Issue
Block a user