mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-12 07:50:25 +00:00
* fix: get_group_info ownerUin is "0" * Add native module loading and improve logging Loaded a native module in NTQQGroupApi and added test calls to sendSsoCmdReqByContend with different parameter types. Changed fileLog default to true in config. Enhanced NativePacketClient with detailed send/receive logging. Updated NodeIKernelMsgService to accept unknown type for sendSsoCmdReqByContend param. Added process PID logging in napcat shell. * feat: new napcat-4.9.0-beta * feat: Add FFmpeg native addon and TypeScript definitions Introduced FFmpeg Node.js native addon binaries for multiple platforms (darwin-arm64, linux-arm64, linux-x64, win-x64) and added TypeScript type definitions for the addon interface, including video info extraction, duration detection, audio conversion, and PCM decoding. * Remove baseClient and simplify packet client selection Deleted baseClient.ts and moved its logic into nativeClient.ts, making NativePacketClient a standalone class. Refactored PacketClientContext to always use NativePacketClient, removing support for multiple packet backends and related selection logic. Updated binary for napi2native.win32.x64.node. * Remove debug log for process PID in napcat.ts Eliminated an unnecessary console.log statement that printed the process PID. This cleans up the output and removes leftover debugging code. * fix: getQQBuildStr * fix: 简化代码 * refactor: 大幅度调整send * feat: ffmpeg enhance for native node addon * Remove baseClient.ts from packet client module Deleted the src/core/packet/client/baseClient.ts file, which contained the PacketClient class and related interfaces. This may be part of a refactor or cleanup to remove unused or redundant code. * Remove 'bmp24' argument from getVideoInfo call Updated the extractThumbnail method to call addon.getVideoInfo without the 'bmp24' argument, aligning with the updated addon API. * refactor: 重构目录删除旧支持 * feat: raw包能力增强完成 * refactor: 规范化 * feat: packet能力增强 * feat: 9.9.22-40824 & 9.9.22-40768 * Refactor addon path resolution and rename Windows addon Simplifies the logic for resolving the ffmpeg addon path by dynamically constructing the filename from process.platform and process.arch. Also renames the Windows x64 addon file to ffmpegAddon.win32.x64.node for consistency. * Add mappings for 3.2.20 versions in napi2native.json Added send and recv address mappings for 3.2.20-x64 and 3.2.20-arm64 builds to support additional versions in napi2native.json. --------- Co-authored-by: Clansty <i@gao4.pw>
130 lines
3.6 KiB
TypeScript
130 lines
3.6 KiB
TypeScript
/**
|
|
* FFmpeg Native Addon Adapter
|
|
* 使用原生 Node.js Addon 实现的 FFmpeg 适配器
|
|
*/
|
|
|
|
import { platform, arch } from 'node:os';
|
|
import path from 'node:path';
|
|
import { existsSync } from 'node:fs';
|
|
import { writeFile } from 'node:fs/promises';
|
|
import type { FFmpeg } from './ffmpeg-addon';
|
|
import type { IFFmpegAdapter, VideoInfoResult } from './ffmpeg-adapter-interface';
|
|
import { dlopen } from 'node:process';
|
|
|
|
/**
|
|
* 获取 Native Addon 路径
|
|
* @param binaryPath 二进制文件路径(来自 pathWrapper.binaryPath)
|
|
*/
|
|
function getAddonPath(binaryPath: string): string {
|
|
const platformName = platform();
|
|
const archName = arch();
|
|
|
|
let addonFileName: string = process.platform + '.' + process.arch;
|
|
let addonPath = path.join(binaryPath, "./native/ffmpeg/", `${addonFileName}.node`);
|
|
if (existsSync(addonPath)) {
|
|
throw new Error(`Unsupported platform: ${platformName} ${archName}`);
|
|
}
|
|
return addonPath;
|
|
}
|
|
|
|
/**
|
|
* FFmpeg Native Addon 适配器实现
|
|
*/
|
|
export class FFmpegAddonAdapter implements IFFmpegAdapter {
|
|
public readonly name = 'FFmpegAddon';
|
|
private addon: FFmpeg | null = null;
|
|
private binaryPath: string;
|
|
|
|
constructor(binaryPath: string) {
|
|
this.binaryPath = binaryPath;
|
|
}
|
|
|
|
/**
|
|
* 检查 Addon 是否可用
|
|
*/
|
|
async isAvailable(): Promise<boolean> {
|
|
try {
|
|
const addonPath = getAddonPath(this.binaryPath);
|
|
if (!existsSync(addonPath)) {
|
|
return false;
|
|
}
|
|
let temp_addon = { exports: {} };
|
|
dlopen(temp_addon, addonPath);
|
|
this.addon = temp_addon.exports as FFmpeg;
|
|
return this.addon !== null;
|
|
} catch (error) {
|
|
console.error('[FFmpegAddonAdapter] Failed to load addon:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private ensureAddon(): FFmpeg {
|
|
if (!this.addon) {
|
|
throw new Error('FFmpeg Addon is not available');
|
|
}
|
|
return this.addon;
|
|
}
|
|
|
|
/**
|
|
* 获取视频信息
|
|
*/
|
|
async getVideoInfo(videoPath: string): Promise<VideoInfoResult> {
|
|
const addon = this.ensureAddon();
|
|
const info = await addon.getVideoInfo(videoPath, 'bmp24');
|
|
|
|
return {
|
|
width: info.width,
|
|
height: info.height,
|
|
duration: info.duration,
|
|
format: info.format,
|
|
thumbnail: info.image,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 获取时长
|
|
*/
|
|
async getDuration(filePath: string): Promise<number> {
|
|
const addon = this.ensureAddon();
|
|
return addon.getDuration(filePath);
|
|
}
|
|
|
|
/**
|
|
* 转换为 PCM
|
|
*/
|
|
async convertToPCM(filePath: string, pcmPath: string): Promise<Buffer> {
|
|
const addon = this.ensureAddon();
|
|
const result = await addon.decodeAudioToPCM(filePath);
|
|
|
|
// 写入文件
|
|
await writeFile(pcmPath, result.pcm);
|
|
|
|
return result.pcm;
|
|
}
|
|
|
|
/**
|
|
* 转换文件
|
|
*/
|
|
async convertFile(inputFile: string, outputFile: string, format: string): Promise<void> {
|
|
const addon = this.ensureAddon();
|
|
|
|
if (format === 'silk' || format === 'ntsilk') {
|
|
// 使用 Addon 的 NTSILK 转换
|
|
await addon.convertToNTSilkTct(inputFile, outputFile);
|
|
} else {
|
|
throw new Error(`Format '${format}' is not supported by FFmpeg Addon`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 提取缩略图
|
|
*/
|
|
async extractThumbnail(videoPath: string, thumbnailPath: string): Promise<void> {
|
|
const addon = this.ensureAddon();
|
|
const info = await addon.getVideoInfo(videoPath);
|
|
|
|
// 将缩略图写入文件
|
|
await writeFile(thumbnailPath, info.image);
|
|
}
|
|
}
|