import { useCallback, useEffect, useRef, useState } from 'react' import toast from 'react-hot-toast' import { CheckCircle2, Download, Loader2, XCircle } from 'lucide-react' import { toolsAPI, type FFmpegToolInfo, type FFmpegToolsStatus } from '../api/tools' // FFToolsPanel 展示 ffmpeg/ffprobe 的安装状态,并提供「一键下载安装」: // 后端自动匹配当前运行环境(OS + 架构),下载到 data 目录并写入设置, // 无需手动填写路径。 export function FFToolsPanel({ onInstalled }: { onInstalled?: () => void }) { const [status, setStatus] = useState(null) const [working, setWorking] = useState(false) const pollingRef = useRef(false) const load = useCallback(async () => { try { setStatus(await toolsAPI.ffToolsStatus()) } catch { // 网络波动时保持旧状态,不打断页面 } }, []) useEffect(() => { load().catch(() => undefined) }, [load]) const installing = Boolean(status?.installing) // 安装进行中:轮询状态直到结束,完成后刷新设置页(路径字段自动填入)。 useEffect(() => { if (!installing || pollingRef.current) return pollingRef.current = true const timer = window.setInterval(async () => { try { const next = await toolsAPI.ffToolsStatus() setStatus(next) if (!next.installing) { window.clearInterval(timer) pollingRef.current = false if (next.error) { toast.error(`FFmpeg 下载安装失败:${next.error}`) } else { toast.success('FFmpeg / FFprobe 下载安装完成,系统已自动使用') onInstalled?.() } } } catch { // 轮询失败继续等下一轮 } }, 1500) return () => { window.clearInterval(timer) pollingRef.current = false } }, [installing, onInstalled]) const install = async () => { setWorking(true) try { const next = await toolsAPI.installFFTools() setStatus(next) if (next.error && !next.installing) { toast.error(next.error) } else if (next.installing) { toast('开始下载,完成后自动生效') } else { toast.success('已检测到可用工具') onInstalled?.() } } catch (err) { toast.error( (err as { response?: { data?: { error?: string } } })?.response?.data?.error ?? (err as { message?: string })?.message ?? '启动下载失败', ) } finally { setWorking(false) } } const busy = working || installing const targetLabel = status?.target?.label ?? '当前平台' const ffmpegInstalled = Boolean(status?.ffmpeg?.installed) const ffprobeInstalled = Boolean(status?.ffprobe?.installed) return (
FFmpeg / FFprobe 工具
当前平台:{targetLabel} · 安装目录: {status?.install_dir ?? '…'}
{(status?.message || status?.error) && (
{status?.error || status?.message}
)} {!ffmpegInstalled || !ffprobeInstalled ? (
未检测到可用工具。点击「下载并安装」后,服务端会自动匹配当前系统下载对应版本,安装完成后无需手动填写路径。
) : null}
) } function ToolRow({ name, info }: { name: string; info?: FFmpegToolInfo }) { return (
{info?.installed ? ( ) : ( )}
{name} {info?.installed ? '' : '(未安装)'}
{info?.installed && (
{info.path}
)} {info?.version &&
{info.version}
}
) }