diff --git a/src/common/helper.ts b/src/common/helper.ts index 67a1a929..25ccb758 100644 --- a/src/common/helper.ts +++ b/src/common/helper.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import fs from 'fs'; import os from 'node:os'; -import { QQLevel } from '@/core'; +import { Peer, QQLevel } from '@/core'; export async function solveProblem any>(func: T, ...args: Parameters): Promise | undefined> { return new Promise | undefined>((resolve) => { @@ -45,7 +45,29 @@ export class UUIDConverter { return { high: high.toString(), low: low.toString() }; } } - +export class FileNapCatOneBotUUID { + static encode(peer: Peer, msgId: string, elementId: string): string { + return `NapCatOneBot-File-${peer.chatType}-${peer.peerUid}-${msgId}-${elementId}`; + } + static decode(uuid: string): undefined | { + peer: Peer, + msgId: string, + elementId: string + } { + if (!uuid.startsWith('NapCatOneBot-File-')) return undefined; + const data = uuid.split('-'); + if (data.length !== 6) return undefined; + const [, , chatType, peerUid, msgId, elementId] = data; + return { + peer: { + chatType: chatType as any, + peerUid: peerUid + }, + msgId, + elementId, + }; + } +} export function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/src/onebot/action/file/GetFile.ts b/src/onebot/action/file/GetFile.ts index 892030bb..b0502d1d 100644 --- a/src/onebot/action/file/GetFile.ts +++ b/src/onebot/action/file/GetFile.ts @@ -1,8 +1,8 @@ import BaseAction from '../BaseAction'; import fs from 'fs/promises'; -import { UUIDConverter } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/helper'; import { ActionName } from '../types'; -import { ChatType, ElementType, Peer, RawMessage } from '@/core/entities'; +import { ChatType, Peer, RawMessage } from '@/core/entities'; import { FromSchema, JSONSchema } from 'json-schema-to-ts'; export interface GetFilePayload { @@ -29,64 +29,44 @@ export class GetFileBase extends BaseAction { payloadSchema: any = GetFileBase_PayloadSchema; async _handle(payload: GetFilePayload): Promise { - const NTQQFriendApi = this.core.apis.FriendApi; - const NTQQUserApi = this.core.apis.UserApi; const NTQQMsgApi = this.core.apis.MsgApi; - const NTQQGroupApi = this.core.apis.GroupApi; const NTQQFileApi = this.core.apis.FileApi; - try { - const uuidData = UUIDConverter.decode(payload.file); - const peerUin = uuidData.high; - const msgId = uuidData.low; - const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin); - let peer: Peer | undefined; - //识别Peer - if (isGroup) { - peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: peerUin }; - } - const PeerUid = await NTQQUserApi.getUidByUinV2(peerUin); - if (PeerUid) { - const isBuddy = await NTQQFriendApi.isBuddy(PeerUid); - if (isBuddy) { - peer = { chatType: ChatType.KCHATTYPEC2C, peerUid: PeerUid }; - } else { - peer = { chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: PeerUid }; - } - } - if (!peer) { - throw new Error('chattype not support'); - } - const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]); - if (msgList.msgList.length == 0) { - throw new Error('msg not found'); - } - 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'); - } - const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', ''); - const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0'; - const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || ''; + + const contextFile = FileNapCatOneBotUUID.decode(payload.file); + + //接收消息标记模式 + if (contextFile) { + const { peer, msgId, elementId } = contextFile; + + const downloadPath = await NTQQFileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', ''); + + const mixElement = (await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList + .find(msg => msg.msgId === msgId)?.elements.find(e => e.elementId === elementId); + const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement ; + if(!mixElementInner) throw new Error('element not found'); + + const fileSize = mixElementInner.fileSize?.toString() || ''; + const fileName = mixElementInner.fileName || ''; + const res: GetFileResponse = { file: downloadPath, url: downloadPath, file_size: fileSize, file_name: fileName, }; - if (/* enableLocalFile2Url && */ downloadPath) { + + if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) { try { res.base64 = await fs.readFile(downloadPath, 'base64'); } catch (e) { throw new Error('文件下载失败. ' + e); } } - //不手动删除?文件持久化了 return res; - } catch { - this.core.context.logger.logDebug('GetFileBase Mode - 1 Error'); } - + //群文件模式 + + //搜索名字模式 const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems; if (NTSearchNameResult.length !== 0) { const MsgId = NTSearchNameResult[0].msgId; @@ -94,9 +74,7 @@ export class GetFileBase extends BaseAction { if (NTSearchNameResult[0].chatType == ChatType.KCHATTYPEGROUP) { peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode }; } - if (!peer) { - throw new Error('chattype not support'); - } + 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'); @@ -113,16 +91,16 @@ export class GetFileBase extends BaseAction { file_size: NTSearchNameResult[0].fileSize.toString(), file_name: NTSearchNameResult[0].fileName, }; - if (/* enableLocalFile2Url && */ downloadPath) { + if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) { try { res.base64 = await fs.readFile(downloadPath, 'base64'); } catch (e) { throw new Error('文件下载失败. ' + e); } } - //不手动删除?文件持久化了 return res; } + throw new Error('file not found'); } } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index a80d3d72..149e4541 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -1,4 +1,4 @@ -import { UUIDConverter } from '@/common/helper'; +import { FileNapCatOneBotUUID } from '@/common/helper'; import { MessageUnique } from '@/common/message-unique'; import { AtType, @@ -98,14 +98,19 @@ export class OneBotMsgApi { } }, - picElement: async (element, msg) => { + picElement: async (element, msg, elementWrapper) => { try { + const peer = { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }; return { type: OB11MessageDataType.image, data: { file: element.fileName, sub_type: element.picSubType, - file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), + file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId), url: await this.core.apis.FileApi.getImageUrl(element), file_size: element.fileSize, }, @@ -117,6 +122,11 @@ export class OneBotMsgApi { }, fileElement: async (element, msg, elementWrapper) => { + const peer = { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }; await this.core.apis.FileApi.addFileCache( { peerUid: msg.peerUid, @@ -137,7 +147,7 @@ export class OneBotMsgApi { file: element.fileName, path: element.filePath, url: element.filePath, - file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), + file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId), file_size: element.fileSize, }, }; @@ -184,11 +194,16 @@ export class OneBotMsgApi { '0', 'marketface', ); + const peer = { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }; return { type: OB11MessageDataType.image, data: { file: 'marketface', - file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), + file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId), path: elementWrapper.elementId, url: elementWrapper.elementId, }, @@ -247,7 +262,11 @@ export class OneBotMsgApi { videoElement: async (element, msg, elementWrapper) => { const NTQQFileApi = this.core.apis.FileApi; - + const peer = { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }; //读取视频链接并兜底 let videoUrlWrappers: Awaited> | undefined; @@ -302,13 +321,18 @@ export class OneBotMsgApi { file: element.fileName, path: videoDownUrl, url: videoDownUrl, - file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), + file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId), file_size: element.fileSize, }, }; }, pttElement: async (element, msg, elementWrapper) => { + const peer = { + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }; await this.core.apis.FileApi.addFileCache( { peerUid: msg.peerUid, @@ -328,7 +352,7 @@ export class OneBotMsgApi { data: { file: element.fileName, path: element.filePath, - file_id: UUIDConverter.encode(msg.peerUin, msg.msgId), + file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId), file_size: element.fileSize, }, };