Files
NapCatQQ/src/onebot/action/file/GetRecord.ts
2024-10-30 21:09:32 +08:00

77 lines
3.1 KiB
TypeScript

import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile';
import { ActionName } from '../types';
import { spawn } from 'node:child_process';
import { promises as fs } from 'fs';
import { decode } from 'silk-wasm';
const FFMPEG_PATH = process.env.FFMPEG_PATH || 'ffmpeg';
const out_format = ['mp3' , 'amr' , 'wma' , 'm4a' , 'spx' , 'ogg' , 'wav' , 'flac'];
type Payload = {
out_format : string
} & GetFilePayload
export default class GetRecord extends GetFileBase {
actionName = ActionName.GetRecord;
async _handle(payload: Payload): Promise<GetFileResponse> {
const res = await super._handle(payload);
if (payload.out_format && typeof payload.out_format === 'string') {
const inputFile = res.file;
if (!inputFile) throw new Error('file not found');
if (!out_format.includes(payload.out_format)) {
throw new Error('转换失败 out_format 字段可能格式不正确');
}
const pcmFile = `${inputFile}.pcm`;
const outputFile = `${inputFile}.${payload.out_format}`;
try {
await fs.access(inputFile);
try {
await fs.access(outputFile);
} catch (error) {
await this.decodeFile(inputFile, pcmFile);
await this.convertFile(pcmFile, outputFile, payload.out_format);
}
const base64Data = await fs.readFile(outputFile, { encoding: 'base64' });
res.file = outputFile;
res.url = outputFile;
res.base64 = base64Data;
} catch (error) {
console.error('Error processing file:', error);
throw error; // 重新抛出错误以便调用者可以处理
}
}
return res;
}
private async decodeFile(inputFile: string, outputFile: string): Promise<void> {
try {
const inputData = await fs.readFile(inputFile);
const decodedData = await decode(inputData, 24000);
await fs.writeFile(outputFile, Buffer.from(decodedData.data));
} catch (error) {
console.error('Error decoding file:', error);
throw error; // 重新抛出错误以便调用者可以处理
}
}
private convertFile(inputFile: string, outputFile: string, format: string): Promise<void> {
return new Promise((resolve, reject) => {
const params = format === 'amr' ? ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, '-ar', '8000', '-b:a', '12.2k', outputFile] : ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, outputFile];
const ffmpeg = spawn(FFMPEG_PATH, params);
ffmpeg.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`ffmpeg process exited with code ${code}`));
}
});
ffmpeg.on('error', (error: Error) => {
reject(error);
});
});
}
}