chore: clean code for file.ts

This commit is contained in:
Wesley F. Young 2024-08-31 13:35:29 +08:00
parent efc1875e35
commit f05cf68945
2 changed files with 61 additions and 122 deletions

View File

@ -16,7 +16,8 @@ export async function getVideoInfo(filePath: string, logger: LogWrapper) {
filePath: string filePath: string
}>((resolve, reject) => { }>((resolve, reject) => {
const ffmpegPath = process.env.FFMPEG_PATH; const ffmpegPath = process.env.FFMPEG_PATH;
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath); if (ffmpegPath)
ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => { ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
if (err) { if (err) {
reject(err); reject(err);

View File

@ -26,10 +26,8 @@ import { calculateFileMD5, isGIF } from '@/common/file';
import pathLib from 'node:path'; import pathLib from 'node:path';
import { defaultVideoThumbB64, getVideoInfo } from '@/common/video'; import { defaultVideoThumbB64, getVideoInfo } from '@/common/video';
import ffmpeg from 'fluent-ffmpeg'; import ffmpeg from 'fluent-ffmpeg';
import fsnormal from 'node:fs';
import { encodeSilk } from '@/common/audio'; import { encodeSilk } from '@/common/audio';
export class NTQQFileApi { export class NTQQFileApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
@ -41,10 +39,6 @@ export class NTQQFileApi {
this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger); this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger);
} }
async getFileType(filePath: string) {
return fileType.fileTypeFromFile(filePath);
}
async copyFile(filePath: string, destPath: string) { async copyFile(filePath: string, destPath: string) {
await this.core.util.copyFile(filePath, destPath); await this.core.util.copyFile(filePath, destPath);
} }
@ -60,18 +54,15 @@ export class NTQQFileApi {
})).urlResult.domainUrl; })).urlResult.domainUrl;
} }
// 上传文件到QQ的文件夹
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) { async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
// napCatCore.wrapper.util.
const fileMd5 = await calculateFileMD5(filePath); const fileMd5 = await calculateFileMD5(filePath);
let ext: string = (await this.getFileType(filePath))?.ext as string || ''; const extOrEmpty = (await fileType.fileTypeFromFile(filePath))?.ext;
if (ext) { const ext = extOrEmpty ? `.${extOrEmpty}` : '';
ext = '.' + ext;
}
let fileName = `${path.basename(filePath)}`; let fileName = `${path.basename(filePath)}`;
if (fileName.indexOf('.') === -1) { if (fileName.indexOf('.') === -1) {
fileName += ext; fileName += ext;
} }
const mediaPath = this.context.session.getMsgService().getRichMediaFilePathForGuild({ const mediaPath = this.context.session.getMsgService().getRichMediaFilePathForGuild({
md5HexStr: fileMd5, md5HexStr: fileMd5,
fileName: fileName, fileName: fileName,
@ -82,6 +73,7 @@ export class NTQQFileApi {
downloadType: 1, downloadType: 1,
file_uuid: '', file_uuid: '',
}); });
await this.copyFile(filePath, mediaPath!); await this.copyFile(filePath, mediaPath!);
const fileSize = await this.getFileSize(filePath); const fileSize = await this.getFileSize(filePath);
return { return {
@ -93,11 +85,7 @@ export class NTQQFileApi {
}; };
} }
async createValidSendFileElement( async createValidSendFileElement(filePath: string, fileName: string = '', folderId: string = '',): Promise<SendFileElement> {
filePath: string,
fileName: string = '',
folderId: string = '',
): Promise<SendFileElement> {
const { const {
fileName: _fileName, fileName: _fileName,
path, path,
@ -118,55 +106,36 @@ export class NTQQFileApi {
}; };
} }
async createValidSendPicElement( async createValidSendPicElement(picPath: string, summary: string = '', subType: 0 | 1 = 0,): Promise<SendPicElement> {
picPath: string, const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
summary: string = '',
subType: 0 | 1 = 0,
): Promise<SendPicElement> {
const {
md5,
fileName,
path,
fileSize,
} = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
if (fileSize === 0) { if (fileSize === 0) {
throw new Error('文件异常大小为0'); throw new Error('文件异常大小为0');
} }
const imageSize = await this.core.apis.FileApi.getImageSize(picPath); const imageSize = await this.core.apis.FileApi.getImageSize(picPath);
const picElement: any = {
md5HexStr: md5,
fileSize: fileSize.toString(),
picWidth: imageSize?.width,
picHeight: imageSize?.height,
fileName: fileName,
sourcePath: path,
original: true,
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
picSubType: subType,
fileUuid: '',
fileSubId: '',
thumbFileSize: 0,
summary,
};
return { return {
elementType: ElementType.PIC, elementType: ElementType.PIC,
elementId: '', elementId: '',
picElement, picElement: {
md5HexStr: md5,
fileSize: fileSize.toString(),
picWidth: imageSize.width,
picHeight: imageSize.height,
fileName: fileName,
sourcePath: path,
original: true,
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
picSubType: subType,
fileUuid: '',
fileSubId: '',
thumbFileSize: 0,
summary,
} as PicElement,
}; };
} }
async createValidSendVideoElement( async createValidSendVideoElement(filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise<SendVideoElement> {
filePath: string,
fileName: string = '',
diyThumbPath: string = '',
): Promise<SendVideoElement> {
const logger = this.core.context.logger; const logger = this.core.context.logger;
const { const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
fileName: _fileName,
path,
fileSize,
md5,
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
if (fileSize === 0) { if (fileSize === 0) {
throw new Error('文件异常大小为0'); throw new Error('文件异常大小为0');
} }
@ -182,9 +151,10 @@ export class NTQQFileApi {
try { try {
videoInfo = await getVideoInfo(path, logger); videoInfo = await getVideoInfo(path, logger);
} catch (e) { } catch (e) {
logger.logError('获取视频信息失败', e); logger.logError('获取视频信息失败,将使用默认值', e);
} }
const createThumb = new Promise<string | undefined>((resolve, reject) => { const thumbPath = new Map();
const _thumbPath = await new Promise<string | undefined>((resolve, reject) => {
const thumbFileName = `${md5}_0.png`; const thumbFileName = `${md5}_0.png`;
const thumbPath = pathLib.join(thumb, thumbFileName); const thumbPath = pathLib.join(thumb, thumbFileName);
ffmpeg(filePath) ffmpeg(filePath)
@ -195,7 +165,7 @@ export class NTQQFileApi {
resolve(thumbPath); resolve(thumbPath);
}).catch(reject); }).catch(reject);
} else { } else {
fsnormal.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64')); fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
resolve(thumbPath); resolve(thumbPath);
} }
}) })
@ -204,31 +174,14 @@ export class NTQQFileApi {
filename: thumbFileName, filename: thumbFileName,
folder: thumb, folder: thumb,
size: videoInfo.width + 'x' + videoInfo.height, size: videoInfo.width + 'x' + videoInfo.height,
}).on('end', () => { })
.on('end', () => {
resolve(thumbPath); resolve(thumbPath);
}); });
}); });
const thumbPath = new Map();
const _thumbPath = await createThumb;
const thumbSize = _thumbPath ? (await fsPromises.stat(_thumbPath)).size : 0; const thumbSize = _thumbPath ? (await fsPromises.stat(_thumbPath)).size : 0;
// log("生成缩略图", _thumbPath)
thumbPath.set(0, _thumbPath); thumbPath.set(0, _thumbPath);
const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : ''; const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : '';
// "fileElement": {
// "fileMd5": "",
// "fileName": "1.mp4",
// "filePath": "C:\\Users\\nanae\\OneDrive\\Desktop\\1.mp4",
// "fileSize": "1847007",
// "picHeight": 1280,
// "picWidth": 720,
// "picThumbPath": {},
// "file10MMd5": "",
// "fileSha": "",
// "fileSha3": "",
// "fileUuid": "",
// "fileSubId": "",
// "thumbFileSize": 750
// }
return { return {
elementType: ElementType.VIDEO, elementType: ElementType.VIDEO,
elementId: '', elementId: '',
@ -243,28 +196,12 @@ export class NTQQFileApi {
thumbWidth: videoInfo.width, thumbWidth: videoInfo.width,
thumbHeight: videoInfo.height, thumbHeight: videoInfo.height,
fileSize: '' + fileSize, fileSize: '' + fileSize,
// fileFormat: videotype
// fileUuid: "",
// transferStatus: 0,
// progress: 0,
// invalidState: 0,
// fileSubId: "",
// fileBizId: null,
// originVideoMd5: "",
// fileFormat: 2,
// import_rich_media_context: null,
// sourceVideoCodecFormat: 2
}, },
}; };
} }
async createValidSendPttElement(pttPath: string): Promise<SendPttElement> { async createValidSendPttElement(pttPath: string): Promise<SendPttElement> {
const { const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
converted,
path: silkPath,
duration,
} = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
// 生成语音 Path: silkPath Time: duration
if (!silkPath) { if (!silkPath) {
throw new Error('语音转换失败, 请检查语音文件是否正常'); throw new Error('语音转换失败, 请检查语音文件是否正常');
} }
@ -283,7 +220,6 @@ export class NTQQFileApi {
filePath: path, filePath: path,
md5HexStr: md5, md5HexStr: md5,
fileSize: fileSize, fileSize: fileSize,
// duration: Math.max(1, Math.round(fileSize / 1024 / 3)), // 一秒钟大概是3kb大小, 小于1秒的按1秒算
duration: duration ?? 1, duration: duration ?? 1,
formatType: 1, formatType: 1,
voiceType: 1, voiceType: 1,
@ -299,9 +235,6 @@ export class NTQQFileApi {
}; };
} }
async downloadMediaByUuid() {
//napCatCore.session.getRichMediaService().downloadFileForFileUuid();
}
async downloadFileForModelId(peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) { async downloadFileForModelId(peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) {
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2( const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelRichMediaService/downloadFileForModelId', 'NodeIKernelRichMediaService/downloadFileForModelId',
@ -314,6 +247,7 @@ export class NTQQFileApi {
); );
return fileTransNotifyInfo.filePath; return fileTransNotifyInfo.filePath;
} }
async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) { async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
//logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force); //logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
// 用于下载收到的消息中的图片等 // 用于下载收到的消息中的图片等
@ -328,7 +262,7 @@ export class NTQQFileApi {
return sourcePath; return sourcePath;
} }
} }
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2( await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelMsgService/downloadRichMedia', 'NodeIKernelMsgService/downloadRichMedia',
'NodeIKernelMsgListener/onRichMediaDownloadComplete', 'NodeIKernelMsgListener/onRichMediaDownloadComplete',
[{ [{
@ -348,13 +282,17 @@ export class NTQQFileApi {
1, 1,
timeout, timeout,
); );
const msg = await this.core.apis.MsgApi.getMsgsByMsgId({ const mixElement = (await this.core.apis.MsgApi.getMsgsByMsgId({
guildId: '', guildId: '',
chatType: chatType, chatType: chatType,
peerUid: peerUid, peerUid: peerUid,
}, [msgId]); }, [msgId])).msgList
const mixElement = msg.msgList.find((msg) => msg.msgId === msgId)?.elements.find((e) => e.elementId === elementId); .find((msg) => msg.msgId === msgId)
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement; ?.elements.find((e) => e.elementId === elementId);
const mixElementInner = mixElement?.videoElement
?? mixElement?.fileElement
?? mixElement?.pttElement
?? mixElement?.picElement;
let realPath = mixElementInner?.filePath; let realPath = mixElementInner?.filePath;
if (!realPath) { if (!realPath) {
const picThumbPath: Map<number, string> = (mixElementInner as any)?.picThumbPath; const picThumbPath: Map<number, string> = (mixElementInner as any)?.picThumbPath;
@ -364,13 +302,17 @@ export class NTQQFileApi {
return realPath; return realPath;
} }
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> { async getImageSize(filePath: string): Promise<ISizeCalculationResult> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
imageSize(filePath, (err, dimensions) => { imageSize(filePath, (err, dimensions) => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
resolve(dimensions); if (!dimensions) {
reject(new Error('获取图片尺寸失败'));
} else {
resolve(dimensions);
}
} }
}); });
}); });
@ -443,11 +385,8 @@ export class NTQQFileApi {
'NodeIKernelFileAssistantListener/onFileSearch', 'NodeIKernelFileAssistantListener/onFileSearch',
[ [
keys, keys,
{ { resultType: 2, pageLimit: 1 },
resultType: 2, randomResultId,
pageLimit: 1,
},
randomResultId
], ],
(ret) => { (ret) => {
searchId = ret; searchId = ret;
@ -463,7 +402,7 @@ export class NTQQFileApi {
fileSize: number = 1024576, fileSize: number = 1024576,
estimatedTime: number = (fileSize * 1000 / 1024576) + 5000, estimatedTime: number = (fileSize * 1000 / 1024576) + 5000,
) { ) {
const [, ret] = await this.core.eventWrapper.callNormalEventV2( const [, fileData] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelFileAssistantService/downloadFile', 'NodeIKernelFileAssistantService/downloadFile',
'NodeIKernelFileAssistantListener/onFileStatusChanged', 'NodeIKernelFileAssistantListener/onFileStatusChanged',
[[fileId]], [[fileId]],
@ -472,7 +411,7 @@ export class NTQQFileApi {
1, 1,
estimatedTime, // estimate 1MB/s estimatedTime, // estimate 1MB/s
); );
return ret.filePath!; return fileData.filePath!;
} }
async getImageUrl(element: PicElement) { async getImageUrl(element: PicElement) {
@ -482,20 +421,19 @@ export class NTQQFileApi {
const url: string = element.originImageUrl!; // 没有域名 const url: string = element.originImageUrl!; // 没有域名
const md5HexStr = element.md5HexStr; const md5HexStr = element.md5HexStr;
const fileMd5 = element.md5HexStr; const fileMd5 = element.md5HexStr;
// const fileUuid = element.fileUuid;
if (url) { if (url) {
const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接 const parsedUrl = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
const imageAppid = UrlParse.searchParams.get('appid'); const imageAppid = parsedUrl.searchParams.get('appid');
const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid); const isNTFlavoredPic = imageAppid && ['1406', '1407'].includes(imageAppid);
if (isNewPic) { if (isNTFlavoredPic) {
let UrlRkey = UrlParse.searchParams.get('rkey'); let rkey = parsedUrl.searchParams.get('rkey');
if (UrlRkey) { if (rkey) {
return IMAGE_HTTP_HOST_NT + url; return IMAGE_HTTP_HOST_NT + url;
} }
const rkeyData = await this.rkeyManager.getRkey(); const rkeyData = await this.rkeyManager.getRkey();
UrlRkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey; rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
return IMAGE_HTTP_HOST_NT + url + `${UrlRkey}`; return IMAGE_HTTP_HOST_NT + url + `${rkey}`;
} else { } else {
// 老的图片url不需要rkey // 老的图片url不需要rkey
return IMAGE_HTTP_HOST + url; return IMAGE_HTTP_HOST + url;