mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
77 lines
3.1 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
}
|
|
}
|