import { GeneralCallResult, InstanceContext, NapCatCore } from '@/napcat-core'; import { createFlashTransferResult, FileListResponse, FlashFileSetInfo, SendStatus, UploadSceneType, } from '@/napcat-core/data/flash'; import { Peer } from '@/napcat-core/types'; export class NTQQFlashApi { context: InstanceContext; core: NapCatCore; constructor (context: InstanceContext, core: NapCatCore) { this.context = context; this.core = core; } /** * 发起闪传上传任务 * @param fileListToUpload 上传文件绝对路径的列表,可以是文件夹!! * @param thumbnailPath * @param filesetName */ async createFlashTransferUploadTask (fileListToUpload: string[], thumbnailPath: string, filesetName: string): Promise { const flashService = this.context.session.getFlashTransferService(); const timestamp: number = Date.now(); const selfInfo = this.core.selfInfo; const fileUploadArg = { screen: 1, // 1 name: filesetName, uploaders: [{ uin: selfInfo.uin, uid: selfInfo.uid, sendEntrance: '', nickname: selfInfo.nick, }], coverPath: thumbnailPath, paths: fileListToUpload, excludePaths: [], expireLeftTime: 0, isNeedDelDeviceInfo: false, isNeedDelLocation: false, coverOriginalInfos: [ { path: fileListToUpload[0] || '', thumbnailPath, }, ], uploadSceneType: UploadSceneType.KUPLOADSCENEAIOFILESELECTOR, // 不知道怎么枚举 先硬编码吧 (PC QQ 10) detectPrivacyInfoResult: { exists: false, allDetectResults: new Map(), }, }; const uploadResult = await flashService.createFlashTransferUploadTask(timestamp, fileUploadArg); if (uploadResult.result === 0) { this.context.logger.log('[Flash] 发起闪传任务成功'); return uploadResult; } else { this.context.logger.logError('[Flash] 发起闪传上传任务失败!!'); return uploadResult; } } /** * 下载闪传文件集 * @param fileSetId */ async downloadFileSetBySetId (fileSetId: string): Promise { const flashService = this.context.session.getFlashTransferService(); const result = await flashService.startFileSetDownload(fileSetId, 1, { isIncludeCompressInnerFiles: false }); // 为了方便,暂时硬编码 if (result.result === 0) { this.context.logger.log('[Flash] 成功开始下载文件集'); } else { this.context.logger.logError('[Flash] 尝试下载文件集失败!'); } return result; } /** * 获取闪传的外链分享 * @param fileSetId */ async getShareLinkBySetId (fileSetId: string): Promise { const flashService = this.context.session.getFlashTransferService(); const result = await flashService.getShareLinkReq(fileSetId); if (result.result === 0) { this.context.logger.log('[Flash] 获取闪传外链分享成功:', result.shareLink); } else { this.context.logger.logError('[Flash] 获取闪传外链失败!!'); } return result; } /** * 从分享外链获取文件集id * @param shareCode */ async fromShareLinkFindSetId (shareCode: string): Promise { const flashService = this.context.session.getFlashTransferService(); const result = await flashService.getFileSetIdByCode(shareCode); if (result.result === 0) { this.context.logger.log('[Flash] 获取shareCode的文件集Id成功!'); } else { this.context.logger.logError('[Flash] 获取文件集ID失败!!'); } return result; } /** * 获取fileSet的文件结构信息 (未来可能需要深度遍历) * == 注意返回结构和其它的不同,没有GeneralCallResult!!! == * @param fileSetId */ async getFileListBySetId (fileSetId: string): Promise { const flashService = this.context.session.getFlashTransferService(); const requestArg = { seq: 0, fileSetId, isUseCache: false, sceneType: 1, // 硬编码 reqInfos: [ { count: 18, // 18 ?? paginationInfo: {}, parentId: '', reqIndexPath: '', reqDepth: 1, filterCondition: { fileCategory: 0, filterType: 0, }, sortConditions: [ { sortField: 0, sortOrder: 0, }, ], isNeedPhysicalInfoReady: false, }, ], }; const result = await flashService.getFileList(requestArg); if (result.rsp.result === 0) { this.context.logger.log('[Flash] 获取fileSet文件信息成功!'); return result.rsp; } else { this.context.logger.logError(`[Flash] 获取文件信息失败:ErrMsg: ${result.rsp.errMs}`); return result.rsp; } } /** * 获取闪传文件集合信息 * @param fileSetId */ async getFileSetIndoBySetId (fileSetId: string): Promise { const flashService = this.context.session.getFlashTransferService(); const requestArg = { fileSetId, }; const result = await flashService.getFileSet(requestArg); if (result.result === 0) { this.context.logger.log('[Flash] 获取闪传文件集信息成功!'); } else { this.context.logger.logError('[Flash] 获取闪传文件信息失败!!'); } return result; } /** * 发送闪传消息(私聊/群聊) * @param fileSetId * @param peer */ async sendFlashMessage (fileSetId: string, peer: Peer): Promise<{ errCode: number, errMsg: string, rsp: { sendStatus: SendStatus[]; }; }> { const flashService = this.context.session.getFlashTransferService(); const target = { destUid: peer.peerUid, destType: peer.chatType, // destUin: peer.peerUin, }; const requestsArg = { fileSetId, targets: [target], }; const result = await flashService.sendFlashTransferMsg(requestsArg); if (result.errCode === 0) { this.context.logger.log('[Flash] 消息发送成功'); } else { this.context.logger.logError(`[Flash] 消息发送失败!!原因:${result.errMsg}`); } return result; } /** * 获取闪传文件集中某个文件的下载URL(外链) * @param fileSetId * @param options */ async getFileTransUrl (fileSetId: string, options: { fileName?: string; fileIndex?: number; }): Promise { const flashService = this.context.session.getFlashTransferService(); const result = await this.getFileListBySetId(fileSetId); const { fileName, fileIndex } = options; let targetFile: any; let file: any; const allFolder = result.fileLists; // eslint-disable-next-line no-labels searchLoop: for (const folder of allFolder) { const fileList = folder.fileList; for (let i = 0; i < fileList.length; i++) { file = fileList[i]; if (fileName !== undefined && file.name === fileName) { targetFile = file; // eslint-disable-next-line no-labels break searchLoop; } if (fileIndex !== undefined && i === fileIndex) { targetFile = file; // eslint-disable-next-line no-labels break searchLoop; } } } if (targetFile === undefined) { this.context.logger.logError('[Flash] 未找到对应文件!!'); return { result: -1, errMsg: '未找到对应文件', transferUrl: '', }; } else { this.context.logger.log('[Flash] 找到对应文件,准备尝试获取传输链接'); const res = await flashService.startFileTransferUrl(targetFile); return { result: 0, errMsg: '', transferUrl: res.url, }; } } async createFileThumbnail (filePath: string): Promise { const msgService = this.context.session.getMsgService(); const savePath = msgService.getFileThumbSavePathForSend(750, true); const result = await this.core.util.createThumbnailImage( 'flashtransfer', filePath, savePath, { width: 520, height: 520, }, 'jpeg', null ); if (result.result === 0) { this.context.logger.log('获取缩略图成功!!'); result.targetPath = savePath; return result; } return result; } }