import { promises as fs } from 'fs'; import os from 'os'; import path from 'path'; import { execFile } from 'child_process'; import { promisify } from 'util'; const execFileAsync = promisify(execFile); export function pickBestPlayAddr(variants: PlayVariant[] | undefined | null) { if (!variants?.length) return null; const best = variants.reduce((best, cur) => { const b1 = best?.bit_rate ?? -1; const b2 = cur?.bit_rate ?? -1; return b2 > b1 ? cur : best; }); return best?.play_addr ?? null; } /** * 使用 ffmpeg 从视频二进制中提取第一帧,返回 JPEG buffer */ export async function extractFirstFrame(videoBuffer: Buffer): Promise<{ buffer: Buffer; contentType: string; ext: string } | null> { const ffmpegCmd = process.env.FFMPEG_PATH || 'ffmpeg'; const tmpDir = os.tmpdir(); const base = `dy_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; const inPath = path.join(tmpDir, `${base}.mp4`); const outPath = path.join(tmpDir, `${base}.jpg`); try { await fs.writeFile(inPath, videoBuffer); const args = [ '-hide_banner', '-loglevel', 'error', '-ss', '0', '-i', inPath, '-frames:v', '1', '-q:v', '2', '-f', 'image2', '-y', outPath, ]; await execFileAsync(ffmpegCmd, args, { windowsHide: true }); const img = await fs.readFile(outPath); return { buffer: img, contentType: 'image/jpeg', ext: 'jpg' }; } catch (e: any) { if (e && (e.code === 'ENOENT' || /not found|is not recognized/i.test(String(e.message)))) { console.warn('系统未检测到 ffmpeg,可安装并配置 PATH 或设置 FFMPEG_PATH 后启用封面提取。'); return null; } throw e; } finally { try { await fs.unlink(inPath); } catch { } try { await fs.unlink(outPath); } catch { } } }