mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0182803ae1 | ||
![]() |
94c1aea6df | ||
![]() |
d143dc043c | ||
![]() |
3f4b0b44cf | ||
![]() |
26fc0c68b2 | ||
![]() |
c1d7aa7aed | ||
![]() |
6aa44bdd79 |
@@ -4,7 +4,7 @@
|
||||
"name": "LLOneBot",
|
||||
"slug": "LLOneBot",
|
||||
"description": "实现 OneBot 11 协议,用以 QQ 机器人开发",
|
||||
"version": "3.29.0",
|
||||
"version": "3.29.2",
|
||||
"icon": "./icon.webp",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -52,6 +52,7 @@ export class ConfigUtil {
|
||||
autoDeleteFile: false,
|
||||
autoDeleteFileSecond: 60,
|
||||
musicSignUrl: '',
|
||||
msgCacheExpire: 120
|
||||
}
|
||||
|
||||
if (!fs.existsSync(this.configPath)) {
|
||||
|
@@ -9,6 +9,8 @@ import { NTQQGroupApi } from '../ntqqapi/api/group'
|
||||
import { log } from './utils/log'
|
||||
import { isNumeric } from './utils/helper'
|
||||
import { NTQQFriendApi, NTQQUserApi } from '../ntqqapi/api'
|
||||
import { RawMessage } from '../ntqqapi/types'
|
||||
import { getConfigUtil } from './config'
|
||||
|
||||
export let groups: Group[] = []
|
||||
export let friends: Friend[] = []
|
||||
@@ -128,3 +130,24 @@ export function getSelfUid() {
|
||||
export function getSelfUin() {
|
||||
return selfInfo['uin']
|
||||
}
|
||||
|
||||
const messages: Map<string, RawMessage> = new Map()
|
||||
let expire: number
|
||||
|
||||
/** 缓存近期消息内容 */
|
||||
export async function addMsgCache(msg: RawMessage) {
|
||||
expire ??= getConfigUtil().getConfig().msgCacheExpire! * 1000
|
||||
if (expire === 0) {
|
||||
return
|
||||
}
|
||||
const id = msg.msgId
|
||||
messages.set(id, msg)
|
||||
setTimeout(() => {
|
||||
messages.delete(id)
|
||||
}, expire)
|
||||
}
|
||||
|
||||
/** 获取近期消息内容 */
|
||||
export function getMsgCache(msgId: string) {
|
||||
return messages.get(msgId)
|
||||
}
|
@@ -30,6 +30,8 @@ export interface Config {
|
||||
ffmpeg?: string // ffmpeg路径
|
||||
musicSignUrl?: string
|
||||
ignoreBeforeLoginMsg?: boolean
|
||||
/** 单位为秒 */
|
||||
msgCacheExpire?: number
|
||||
}
|
||||
|
||||
export interface LLOneBotError {
|
||||
@@ -41,11 +43,10 @@ export interface LLOneBotError {
|
||||
|
||||
export interface FileCache {
|
||||
fileName: string
|
||||
filePath: string
|
||||
fileSize: string
|
||||
fileUuid?: string
|
||||
url?: string
|
||||
msgId?: string
|
||||
msgId: string
|
||||
peerUid: string
|
||||
chatType: number
|
||||
elementId: string
|
||||
downloadFunc?: () => Promise<void>
|
||||
elementType: number
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ export class NTEventWrapper {
|
||||
if (typeof target[prop] === 'undefined') {
|
||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||
return (...args: any[]) => {
|
||||
current.DispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then()
|
||||
current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then()
|
||||
}
|
||||
}
|
||||
// 如果方法存在,正常返回
|
||||
@@ -48,7 +48,7 @@ export class NTEventWrapper {
|
||||
this.WrapperSession = WrapperSession
|
||||
}
|
||||
|
||||
CreatEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||
createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||
const eventNameArr = eventName.split('/')
|
||||
type eventType = {
|
||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
|
||||
@@ -69,16 +69,14 @@ export class NTEventWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
createEventFunction = this.CreatEventFunction
|
||||
|
||||
CreatListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||
createListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||
const ListenerType = this.ListenerMap![listenerMainName]
|
||||
let Listener = this.ListenerManger.get(listenerMainName + uniqueCode)
|
||||
if (!Listener && ListenerType) {
|
||||
Listener = new ListenerType(this.createProxyDispatch(listenerMainName))
|
||||
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1]
|
||||
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener'
|
||||
const addfunc = this.CreatEventFunction<(listener: T) => number>(Service)
|
||||
const addfunc = this.createEventFunction<(listener: T) => number>(Service)
|
||||
addfunc!(Listener as T)
|
||||
//console.log(addfunc!(Listener as T))
|
||||
this.ListenerManger.set(listenerMainName + uniqueCode, Listener)
|
||||
@@ -87,7 +85,7 @@ export class NTEventWrapper {
|
||||
}
|
||||
|
||||
//统一回调清理事件
|
||||
async DispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||
//console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args)
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.forEach((task, uuid) => {
|
||||
//console.log(task.func, uuid, task.createtime, task.timeout)
|
||||
@@ -103,7 +101,7 @@ export class NTEventWrapper {
|
||||
|
||||
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||
const EventFunc = this.CreatEventFunction<EventType>(EventName)
|
||||
const EventFunc = this.createEventFunction<EventType>(EventName)
|
||||
let complete = false
|
||||
const Timeouter = setTimeout(() => {
|
||||
if (!complete) {
|
||||
@@ -152,7 +150,7 @@ export class NTEventWrapper {
|
||||
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map())
|
||||
}
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak)
|
||||
this.CreatListenerFunction(ListenerMainName)
|
||||
this.createListenerFunction(ListenerMainName)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -198,8 +196,8 @@ export class NTEventWrapper {
|
||||
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map())
|
||||
}
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak)
|
||||
this.CreatListenerFunction(ListenerMainName)
|
||||
const EventFunc = this.CreatEventFunction<EventType>(EventName)
|
||||
this.createListenerFunction(ListenerMainName)
|
||||
const EventFunc = this.createEventFunction<EventType>(EventName)
|
||||
retEvent = await EventFunc!(...(args as any[]))
|
||||
})
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import SQLite from '@minatojs/driver-sqlite'
|
||||
import fsPromise from 'node:fs/promises'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { FileCache } from '../types'
|
||||
|
||||
interface SQLiteTables extends Tables {
|
||||
message: {
|
||||
@@ -15,6 +16,7 @@ interface SQLiteTables extends Tables {
|
||||
chatType: number
|
||||
peerUid: string
|
||||
}
|
||||
file: FileCache
|
||||
}
|
||||
|
||||
interface MsgIdAndPeerByShortId {
|
||||
@@ -50,6 +52,17 @@ class MessageUniqueWrapper {
|
||||
}, {
|
||||
primary: 'shortId'
|
||||
})
|
||||
database.extend('file', {
|
||||
fileName: 'string',
|
||||
fileSize: 'string',
|
||||
msgId: 'string(24)',
|
||||
peerUid: 'string(24)',
|
||||
chatType: 'unsigned',
|
||||
elementId: 'string(24)',
|
||||
elementType: 'unsigned',
|
||||
}, {
|
||||
primary: 'fileName'
|
||||
})
|
||||
this.db = database
|
||||
}
|
||||
|
||||
@@ -128,6 +141,14 @@ class MessageUniqueWrapper {
|
||||
this.msgIdMap.resize(maxSize)
|
||||
this.msgDataMap.resize(maxSize)
|
||||
}
|
||||
|
||||
addFileCache(data: FileCache) {
|
||||
return this.db?.upsert('file', [data], 'fileName')
|
||||
}
|
||||
|
||||
getFileCache(fileName: string) {
|
||||
return this.db?.get('file', { fileName })
|
||||
}
|
||||
}
|
||||
|
||||
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper()
|
@@ -21,7 +21,8 @@ import {
|
||||
setSelfInfo,
|
||||
getSelfInfo,
|
||||
getSelfUid,
|
||||
getSelfUin
|
||||
getSelfUin,
|
||||
addMsgCache
|
||||
} from '../common/data'
|
||||
import { hookNTQQApiCall, hookNTQQApiReceive, ReceiveCmdS, registerReceiveHook, startHook } from '../ntqqapi/hook'
|
||||
import { OB11Constructor } from '../onebot11/constructor'
|
||||
@@ -95,7 +96,7 @@ function onLoad() {
|
||||
}
|
||||
ipcMain.handle(CHANNEL_ERROR, async (event, arg) => {
|
||||
const ffmpegOk = await checkFfmpeg(getConfigUtil().getConfig().ffmpeg)
|
||||
llonebotError.ffmpegError = ffmpegOk ? '' : '没有找到ffmpeg,音频只能发送wav和silk,视频尺寸可能异常'
|
||||
llonebotError.ffmpegError = ffmpegOk ? '' : '没有找到 FFmpeg, 音频只能发送 WAV 和 SILK, 视频尺寸可能异常'
|
||||
let { httpServerError, wsServerError, otherError, ffmpegError } = llonebotError
|
||||
let error = `${otherError}\n${httpServerError}\n${wsServerError}\n${ffmpegError}`
|
||||
error = error.replace('\n\n', '\n')
|
||||
@@ -159,6 +160,7 @@ function onLoad() {
|
||||
peerUid: message.peerUid
|
||||
}
|
||||
message.msgShortId = MessageUnique.createMsg(peer, message.msgId)
|
||||
addMsgCache(message)
|
||||
|
||||
OB11Constructor.message(message)
|
||||
.then((msg) => {
|
||||
@@ -183,7 +185,7 @@ function onLoad() {
|
||||
}
|
||||
})
|
||||
OB11Constructor.PrivateEvent(message).then((privateEvent) => {
|
||||
log(message)
|
||||
//log(message)
|
||||
if (privateEvent) {
|
||||
// log("post private event", privateEvent);
|
||||
postOb11Event(privateEvent)
|
||||
|
@@ -179,7 +179,6 @@ export class NTQQFileApi {
|
||||
const url: string = element.originImageUrl! // 没有域名
|
||||
const md5HexStr = element.md5HexStr
|
||||
const fileMd5 = element.md5HexStr
|
||||
const fileUuid = element.fileUuid
|
||||
|
||||
if (url) {
|
||||
const UrlParse = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接
|
||||
|
@@ -3,9 +3,9 @@ import fsPromise from 'node:fs/promises'
|
||||
import { getConfigUtil } from '@/common/config'
|
||||
import { NTQQFileApi, NTQQGroupApi, NTQQUserApi, NTQQFriendApi, NTQQMsgApi } from '@/ntqqapi/api'
|
||||
import { ActionName } from '../types'
|
||||
import { RawMessage } from '@/ntqqapi/types'
|
||||
import { UUIDConverter } from '@/common/utils/helper'
|
||||
import { Peer, ChatType, ElementType } from '@/ntqqapi/types'
|
||||
import { MessageUnique } from '@/common/utils/MessageUnique'
|
||||
|
||||
export interface GetFilePayload {
|
||||
file: string // 文件名或者fileUuid
|
||||
@@ -51,10 +51,10 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
|
||||
throw new Error('chattype not support')
|
||||
}
|
||||
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId])
|
||||
if (msgList.msgList.length == 0) {
|
||||
if (msgList.msgList.length === 0) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
const msg = msgList.msgList[0];
|
||||
const msg = msgList.msgList[0]
|
||||
const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT)
|
||||
if (!findEle) {
|
||||
throw new Error('element not found')
|
||||
@@ -68,7 +68,7 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
|
||||
file_size: fileSize,
|
||||
file_name: fileName,
|
||||
}
|
||||
if (enableLocalFile2Url) {
|
||||
if (enableLocalFile2Url && downloadPath) {
|
||||
try {
|
||||
res.base64 = await fsPromise.readFile(downloadPath, 'base64')
|
||||
} catch (e) {
|
||||
@@ -82,33 +82,42 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
|
||||
|
||||
}
|
||||
|
||||
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems
|
||||
if (NTSearchNameResult.length !== 0) {
|
||||
const MsgId = NTSearchNameResult[0].msgId
|
||||
let peer: Peer | undefined = undefined
|
||||
if (NTSearchNameResult[0].chatType == ChatType.group) {
|
||||
peer = { chatType: ChatType.group, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode }
|
||||
}
|
||||
if (!peer) {
|
||||
throw new Error('chattype not support')
|
||||
}
|
||||
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList
|
||||
if (!msgList || msgList.length == 0) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
const msg = msgList[0]
|
||||
const file = msg.elements.filter(e => e.elementType == NTSearchNameResult[0].elemType)
|
||||
if (file.length == 0) {
|
||||
throw new Error('file not found')
|
||||
}
|
||||
const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '')
|
||||
const fileCache = await MessageUnique.getFileCache(String(payload.file))
|
||||
if (fileCache?.length) {
|
||||
const downloadPath = await NTQQFileApi.downloadMedia(
|
||||
fileCache[0].msgId,
|
||||
fileCache[0].chatType,
|
||||
fileCache[0].peerUid,
|
||||
fileCache[0].elementId,
|
||||
'',
|
||||
''
|
||||
)
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
url: downloadPath,
|
||||
file_size: NTSearchNameResult[0].fileSize.toString(),
|
||||
file_name: NTSearchNameResult[0].fileName,
|
||||
file_size: fileCache[0].fileSize,
|
||||
file_name: fileCache[0].fileName,
|
||||
}
|
||||
if (enableLocalFile2Url) {
|
||||
const peer: Peer = {
|
||||
chatType: fileCache[0].chatType,
|
||||
peerUid: fileCache[0].peerUid,
|
||||
guildId: ''
|
||||
}
|
||||
if (fileCache[0].elementType === ElementType.PIC) {
|
||||
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [fileCache[0].msgId])
|
||||
if (msgList.msgList.length === 0) {
|
||||
throw new Error('msg not found')
|
||||
}
|
||||
const msg = msgList.msgList[0]
|
||||
const findEle = msg.elements.find(e => e.elementId === fileCache[0].elementId)
|
||||
if (!findEle) {
|
||||
throw new Error('element not found')
|
||||
}
|
||||
res.url = await NTQQFileApi.getImageUrl(findEle.picElement)
|
||||
} else if (fileCache[0].elementType === ElementType.VIDEO) {
|
||||
res.url = await NTQQFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId)
|
||||
}
|
||||
if (enableLocalFile2Url && downloadPath && res.file === res.url) {
|
||||
try {
|
||||
res.base64 = await fsPromise.readFile(downloadPath, 'base64')
|
||||
} catch (e) {
|
||||
|
@@ -3,4 +3,11 @@ import { ActionName } from '../types'
|
||||
|
||||
export default class GetImage extends GetFileBase {
|
||||
actionName = ActionName.GetImage
|
||||
|
||||
protected async _handle(payload: { file: string }) {
|
||||
if (!payload.file) {
|
||||
throw new Error('参数 file 不能为空')
|
||||
}
|
||||
return super._handle(payload)
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import BaseAction from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { NTQQMsgApi } from '@/ntqqapi/api'
|
||||
import { MessageUnique } from '@/common/utils/MessageUnique'
|
||||
import { getMsgCache } from '@/common/data'
|
||||
|
||||
export interface PayloadType {
|
||||
message_id: number | string
|
||||
@@ -29,12 +30,9 @@ class GetMsg extends BaseAction<PayloadType, OB11Message> {
|
||||
peerUid: msgIdWithPeer.Peer.peerUid,
|
||||
chatType: msgIdWithPeer.Peer.chatType
|
||||
}
|
||||
const msg = await NTQQMsgApi.getMsgsByMsgId(
|
||||
peer,
|
||||
[msgIdWithPeer?.MsgId || payload.message_id.toString()]
|
||||
)
|
||||
const retMsg = await OB11Constructor.message(msg.msgList[0])
|
||||
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgList[0].msgId)!
|
||||
const msg = getMsgCache(msgIdWithPeer.MsgId) ?? (await NTQQMsgApi.getMsgsByMsgId(peer, [msgIdWithPeer.MsgId])).msgList[0]
|
||||
const retMsg = await OB11Constructor.message(msg)
|
||||
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgId)!
|
||||
retMsg.message_seq = retMsg.message_id
|
||||
retMsg.real_id = retMsg.message_id
|
||||
return retMsg
|
||||
|
@@ -119,9 +119,8 @@ export async function createSendElements(
|
||||
if (!peer) {
|
||||
continue
|
||||
}
|
||||
let atQQ = sendMsg.data?.qq
|
||||
if (atQQ) {
|
||||
atQQ = atQQ.toString()
|
||||
if (sendMsg.data?.qq) {
|
||||
const atQQ = String(sendMsg.data.qq)
|
||||
if (atQQ === 'all') {
|
||||
// todo:查询剩余的at全体次数
|
||||
const groupCode = peer.peerUid
|
||||
@@ -161,7 +160,7 @@ export async function createSendElements(
|
||||
}
|
||||
break
|
||||
case OB11MessageDataType.reply: {
|
||||
if (sendMsg.data.id) {
|
||||
if (sendMsg.data?.id) {
|
||||
const replyMsgId = await MessageUnique.getMsgIdAndPeerByShortId(+sendMsg.data.id)
|
||||
if (!replyMsgId) {
|
||||
log('回复消息不存在', replyMsgId)
|
||||
|
@@ -184,21 +184,30 @@ export class OB11Constructor {
|
||||
}
|
||||
else if (element.picElement) {
|
||||
message_data['type'] = OB11MessageDataType.image
|
||||
let fileName = element.picElement.fileName
|
||||
const isGif = element.picElement.picType === PicType.gif
|
||||
const { picElement } = element
|
||||
/*let fileName = picElement.fileName
|
||||
const isGif = picElement.picType === PicType.gif
|
||||
if (isGif && !fileName.endsWith('.gif')) {
|
||||
fileName += '.gif'
|
||||
}
|
||||
message_data['data']['file'] = fileName
|
||||
message_data['data']['subType'] = element.picElement.picSubType
|
||||
}*/
|
||||
message_data['data']['file'] = picElement.fileName
|
||||
message_data['data']['subType'] = picElement.picSubType
|
||||
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId)
|
||||
message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement)
|
||||
message_data['data']['file_size'] = element.picElement.fileSize
|
||||
message_data['data']['url'] = await NTQQFileApi.getImageUrl(picElement)
|
||||
message_data['data']['file_size'] = picElement.fileSize
|
||||
MessageUnique.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
chatType: msg.chatType,
|
||||
elementId: element.elementId,
|
||||
elementType: element.elementType,
|
||||
fileName: picElement.fileName,
|
||||
fileSize: String(picElement.fileSize || '0'),
|
||||
})
|
||||
}
|
||||
else if (element.videoElement || element.fileElement) {
|
||||
const videoOrFileElement = element.videoElement || element.fileElement
|
||||
const ob11MessageDataType = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file
|
||||
message_data['type'] = ob11MessageDataType
|
||||
message_data['type'] = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file
|
||||
message_data['data']['file'] = videoOrFileElement.fileName
|
||||
message_data['data']['path'] = videoOrFileElement.filePath
|
||||
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId)
|
||||
@@ -210,40 +219,32 @@ export class OB11Constructor {
|
||||
}, msg.msgId, element.elementId,
|
||||
)
|
||||
}
|
||||
NTQQFileApi.addFileCache(
|
||||
{
|
||||
peerUid: msg.peerUid,
|
||||
chatType: msg.chatType,
|
||||
guildId: '',
|
||||
},
|
||||
msg.msgId,
|
||||
msg.msgSeq,
|
||||
msg.senderUid,
|
||||
element.elementId,
|
||||
element.elementType.toString(),
|
||||
videoOrFileElement.fileSize || '0',
|
||||
videoOrFileElement.fileName,
|
||||
)
|
||||
MessageUnique.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
chatType: msg.chatType,
|
||||
elementId: element.elementId,
|
||||
elementType: element.elementType,
|
||||
fileName: videoOrFileElement.fileName,
|
||||
fileSize: String(videoOrFileElement.fileSize || '0')
|
||||
})
|
||||
}
|
||||
else if (element.pttElement) {
|
||||
message_data['type'] = OB11MessageDataType.voice
|
||||
message_data['data']['file'] = element.pttElement.fileName
|
||||
message_data['data']['path'] = element.pttElement.filePath
|
||||
const { pttElement } = element
|
||||
message_data['data']['file'] = pttElement.fileName
|
||||
message_data['data']['path'] = pttElement.filePath
|
||||
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId)
|
||||
message_data['data']['file_size'] = element.pttElement.fileSize
|
||||
NTQQFileApi.addFileCache({
|
||||
message_data['data']['file_size'] = pttElement.fileSize
|
||||
MessageUnique.addFileCache({
|
||||
peerUid: msg.peerUid,
|
||||
msgId: msg.msgId,
|
||||
chatType: msg.chatType,
|
||||
guildId: '',
|
||||
},
|
||||
msg.msgId,
|
||||
msg.msgSeq,
|
||||
msg.senderUid,
|
||||
element.elementId,
|
||||
element.elementType.toString(),
|
||||
element.pttElement.fileSize || '0',
|
||||
element.pttElement.fileUuid || '',
|
||||
)
|
||||
elementId: element.elementId,
|
||||
elementType: element.elementType,
|
||||
fileName: pttElement.fileName,
|
||||
fileSize: String(pttElement.fileSize || '0')
|
||||
})
|
||||
}
|
||||
else if (element.arkElement) {
|
||||
message_data['type'] = OB11MessageDataType.json
|
||||
@@ -589,21 +590,19 @@ export class OB11Constructor {
|
||||
msg: RawMessage,
|
||||
shortId: number
|
||||
): Promise<OB11FriendRecallNoticeEvent | OB11GroupRecallNoticeEvent | undefined> {
|
||||
let msgElement = msg.elements.find(
|
||||
const 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) {
|
||||
if (msg.chatType === ChatType.group) {
|
||||
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!),
|
||||
parseInt(msg.senderUin!),
|
||||
parseInt(operator?.uin || msg.senderUin!),
|
||||
shortId,
|
||||
)
|
||||
}
|
||||
|
@@ -219,6 +219,11 @@ async function onSettingWindowCreated(view: Element) {
|
||||
`${window.LiteLoader.plugins['LLOneBot'].path.data}/logs`,
|
||||
SettingButton('打开', 'config-open-log-path'),
|
||||
),
|
||||
SettingItem(
|
||||
'消息内容缓存时长',
|
||||
'单位为秒,可用于获取撤回的消息',
|
||||
`<div class="q-input"><input class="q-input__inner" data-config-key="msgCacheExpire" type="number" min="1" value="${config.msgCacheExpire}" placeholder="${config.msgCacheExpire}" /></div>`,
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
SettingItem('GitHub 仓库', `https://github.com/LLOneBot/LLOneBot`, SettingButton('点个星星', 'open-github')),
|
||||
|
@@ -1 +1 @@
|
||||
export const version = '3.29.0'
|
||||
export const version = '3.29.2'
|
||||
|
Reference in New Issue
Block a user