Merge branch 'main' into refactor-config-webui

This commit is contained in:
手瓜一十雪 2024-11-16 11:35:59 +08:00 committed by GitHub
commit 046afc0c23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 34 deletions

View File

@ -49,9 +49,10 @@
}, },
"dependencies": { "dependencies": {
"express": "^5.0.0", "express": "^5.0.0",
"fluent-ffmpeg": "^2.1.2",
"qrcode-terminal": "^0.12.0",
"silk-wasm": "^3.6.1", "silk-wasm": "^3.6.1",
"ws": "^8.18.0", "ws": "^8.18.0",
"qrcode-terminal": "^0.12.0", "piscina": "^4.7.0"
"fluent-ffmpeg": "^2.1.2"
} }
} }

View File

@ -0,0 +1,9 @@
import { encode } from "silk-wasm";
export interface EncodeArgs {
input: ArrayBufferView | ArrayBuffer
sampleRate: number
}
export default async ({ input, sampleRate }: EncodeArgs) => {
return await encode(input, sampleRate);
};

View File

@ -1,13 +1,19 @@
import Piscina from 'piscina';
import fsPromise from 'fs/promises'; import fsPromise from 'fs/promises';
import path from 'node:path'; import path from 'node:path';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { spawn } from 'node:child_process'; import { spawn } from 'node:child_process';
import { encode, getDuration, getWavFileInfo, isSilk, isWav } from 'silk-wasm'; import { EncodeResult, getDuration, getWavFileInfo, isSilk, isWav } from 'silk-wasm';
import { LogWrapper } from './log'; import { LogWrapper } from './log';
import { EncodeArgs } from "@/common/audio-worker";
const ALLOW_SAMPLE_RATE = [8000, 12000, 16000, 24000, 32000, 44100, 48000]; const ALLOW_SAMPLE_RATE = [8000, 12000, 16000, 24000, 32000, 44100, 48000];
const EXIT_CODES = [0, 255]; const EXIT_CODES = [0, 255];
const FFMPEG_PATH = process.env.FFMPEG_PATH || 'ffmpeg'; const FFMPEG_PATH = process.env.FFMPEG_PATH ?? 'ffmpeg';
const piscina = new Piscina<EncodeArgs, EncodeResult>({
filename: new URL('./audio-worker.mjs', import.meta.url).href,
});
async function guessDuration(pttPath: string, logger: LogWrapper) { async function guessDuration(pttPath: string, logger: LogWrapper) {
const pttFileInfo = await fsPromise.stat(pttPath); const pttFileInfo = await fsPromise.stat(pttPath);
@ -41,8 +47,11 @@ async function convert(filePath: string, pcmPath: string, logger: LogWrapper): P
} }
async function handleWavFile( async function handleWavFile(
file: Buffer, filePath: string, pcmPath: string, logger: LogWrapper file: Buffer,
): Promise<{input: Buffer, sampleRate: number}> { filePath: string,
pcmPath: string,
logger: LogWrapper
): Promise<{ input: Buffer; sampleRate: number }> {
const { fmt } = getWavFileInfo(file); const { fmt } = getWavFileInfo(file);
if (!ALLOW_SAMPLE_RATE.includes(fmt.sampleRate)) { if (!ALLOW_SAMPLE_RATE.includes(fmt.sampleRate)) {
return { input: await convert(filePath, pcmPath, logger), sampleRate: 24000 }; return { input: await convert(filePath, pcmPath, logger), sampleRate: 24000 };
@ -60,8 +69,8 @@ export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: Log
const { input, sampleRate } = isWav(file) const { input, sampleRate } = isWav(file)
? (await handleWavFile(file, filePath, pcmPath, logger)) ? (await handleWavFile(file, filePath, pcmPath, logger))
: { input: await convert(filePath, pcmPath, logger), sampleRate: 24000 }; : { input: await convert(filePath, pcmPath, logger), sampleRate: 24000 };
const silk = await encode(input, sampleRate); const silk = await piscina.run({ input: input, sampleRate: sampleRate });
await fsPromise.writeFile(pttPath, silk.data); await fsPromise.writeFile(pttPath, Buffer.from(silk.data));
logger.log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration); logger.log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration);
return { return {
converted: true, converted: true,
@ -86,4 +95,4 @@ export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: Log
logger.logError.bind(logger)('convert silk failed', error.stack); logger.logError.bind(logger)('convert silk failed', error.stack);
return {}; return {};
} }
} }

View File

@ -3,12 +3,14 @@ import { defineConfig, PluginOption, UserConfig } from 'vite';
import { resolve } from 'path'; import { resolve } from 'path';
import nodeResolve from '@rollup/plugin-node-resolve'; import nodeResolve from '@rollup/plugin-node-resolve';
import { builtinModules } from 'module'; import { builtinModules } from 'module';
//依赖排除
const external = ['silk-wasm', 'ws', 'express', 'qrcode-terminal', 'fluent-ffmpeg']; const external = ['silk-wasm', 'ws', 'express', 'qrcode-terminal', 'fluent-ffmpeg', 'piscina'];
const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat(); const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].flat();
function genCpModule(module: string) { function genCpModule(module: string) {
return { src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false }; return { src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false };
} }
let startScripts: string[] | undefined = undefined; let startScripts: string[] | undefined = undefined;
if (process.env.NAPCAT_BUILDSYS == 'linux') { if (process.env.NAPCAT_BUILDSYS == 'linux') {
startScripts = []; startScripts = [];
@ -17,6 +19,7 @@ if (process.env.NAPCAT_BUILDSYS == 'linux') {
} else { } else {
startScripts = ['./script/KillQQ.bat']; startScripts = ['./script/KillQQ.bat'];
} }
const FrameworkBaseConfigPlugin: PluginOption[] = [ const FrameworkBaseConfigPlugin: PluginOption[] = [
cp({ cp({
targets: [ targets: [
@ -60,18 +63,18 @@ const ShellBaseConfig = () =>
'./lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg', './lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg',
}, },
}, },
build: { },
sourcemap: false, build: {
target: 'esnext', sourcemap: false,
minify: false, target: 'esnext',
lib: { minify: false,
entry: 'src/shell/napcat.ts', lib: {
formats: ['es'], entry: {
fileName: () => 'napcat.mjs', 'napcat': 'src/shell/napcat.ts',
}, 'audio-worker': 'src/common/audio-worker.ts',
rollupOptions: {
external: [...nodeModules, ...external],
}, },
formats: ['es'],
fileName: (_, entryName) => `${entryName}.mjs`,
}, },
}); });
@ -85,18 +88,18 @@ const FrameworkBaseConfig = () =>
'./lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg', './lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg',
}, },
}, },
build: { },
sourcemap: false, build: {
target: 'esnext', sourcemap: false,
minify: false, target: 'esnext',
lib: { minify: false,
entry: 'src/framework/napcat.ts', lib: {
formats: ['es'], entry: {
fileName: () => 'napcat.mjs', 'napcat': 'src/framework/napcat.ts',
}, 'audio-worker': 'src/common/audio-worker.ts',
rollupOptions: {
external: [...nodeModules, ...external],
}, },
formats: ['es'],
fileName: (_, entryName) => `${entryName}.mjs`,
}, },
}); });