import { ChevronDown, ChevronRight, Folder } from "lucide-react" import { useState } from "react" import { useTranslation } from "react-i18next" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Progress } from "@/components/ui/progress" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { TimelineProject } from "@/features/timeline/types/timeline" import { cn } from "@/lib/utils" import { OutputFormat } from "@/types/video-compiler" import { FORMAT_OPTIONS, FRAME_RATE_OPTIONS, RESOLUTION_PRESETS } from "../constants/export-constants" import { ExportProgress, ExportSettings } from "../types/export-types" import { TransitionExportSettings } from "../types/transition-export-types" import { ExportPresets } from "./export-presets" import { TransitionExportSettingsComponent } from "./transition-export-settings" interface DetailedExportInterfaceProps { settings: TransitionExportSettings & { exportVideo?: boolean exportAudio?: boolean bitrateMode?: "auto" | "limit" bitrate?: number encodingProfile?: "main" | "main10" | "high" entropyMode?: "cabac" | "cavlc" keyframeMode?: "auto" | "every" keyframeInterval?: number optimizeForSpeed?: boolean optimizeForNetwork?: boolean multipassEncoding?: boolean frameReordering?: boolean useVerticalResolution?: boolean useProxyMedia?: boolean renderWithoutTimecode?: boolean interlacedRendering?: boolean normalizeAudio?: boolean audioTarget?: number audioCodec?: string audioChannels?: string embedInfoAsProject?: boolean chaptersByMarkers?: boolean } onSettingsChange: (updates: Partial) => void onChooseFolder: () => void onExport: () => void onCancelExport: () => void onClose: () => void isRendering: boolean renderProgress: ExportProgress | null hasProject: boolean project?: TimelineProject } export function DetailedExportInterface({ settings, onSettingsChange, onChooseFolder, onExport, onCancelExport, onClose, isRendering, renderProgress, hasProject, project, }: DetailedExportInterfaceProps) { const { t } = useTranslation() const [selectedPresetId, setSelectedPresetId] = useState("custom") const [showAdvancedSettings, setShowAdvancedSettings] = useState(false) const [showSubtitlesSettings, setShowSubtitlesSettings] = useState(false) const [renderMode, setRenderMode] = useState<"single" | "individual">("single") const [activeTab, setActiveTab] = useState<"video" | "audio" | "file" | "transitions">("video") // Обработчик выбора пресета const handlePresetSelect = (preset: any) => { setSelectedPresetId(preset.id) if (preset.id !== "custom") { // Применяем настройки пресета const updates: Partial = {} if (preset.settings.format) { updates.format = preset.settings.format } if (preset.settings.codec) { // Устанавливаем кодек в зависимости от формата if (preset.settings.format === OutputFormat.Mov && preset.settings.codec === "prores") { // ProRes настройки updates.encodingProfile = undefined } else if (preset.settings.codec === "h264") { updates.encodingProfile = preset.settings.codecProfile || "high" } else if (preset.settings.codec === "h265") { updates.encodingProfile = preset.settings.codecProfile || "main10" } } if (preset.settings.resolution && preset.settings.resolution !== "timeline") { updates.resolution = preset.settings.resolution } if (preset.settings.fps && preset.settings.fps !== "timeline") { updates.frameRate = preset.settings.fps } if (preset.settings.useHardwareAcceleration !== undefined) { updates.enableGPU = preset.settings.useHardwareAcceleration } if (preset.settings.useVerticalResolution !== undefined) { updates.useVerticalResolution = preset.settings.useVerticalResolution } if (preset.settings.normalizeAudio !== undefined) { updates.normalizeAudio = preset.settings.normalizeAudio } if (preset.settings.audioTarget !== undefined) { updates.audioTarget = preset.settings.audioTarget } if (preset.settings.bitrate !== undefined) { updates.bitrate = preset.settings.bitrate updates.bitrateMode = preset.settings.bitrateMode || "limit" } if (preset.settings.optimizeForSpeed !== undefined) { updates.optimizeForSpeed = preset.settings.optimizeForSpeed } onSettingsChange(updates) } } return (
{/* Пресеты */}
{/* File Name */}
onSettingsChange({ fileName: e.target.value })} disabled={isRendering} />
{/* Save Location */}
{/* Режим рендеринга */}
setRenderMode(v as any)}>
{/* Вкладки Видео/Аудио/Файл/Переходы */} setActiveTab(v as any)} className="w-full"> {t("dialogs.export.video")} {t("dialogs.export.audio")} {t("dialogs.export.file")} {t("dialogs.export.transitions")} {/* Checkbox Экспорт видео */}
onSettingsChange({ exportVideo: checked as boolean })} />
{/* Формат */}
{/* Кодек */}
{/* Тип кодека (для ProRes) */} {settings.format === OutputFormat.Mov && (
)} {/* Чекбоксы для видео */}
onSettingsChange({ interlacedRendering: checked as boolean })} />
onSettingsChange({ optimizeForNetwork: checked as boolean })} />
{/* Разрешение */}
{/* Ручной ввод разрешения для Timeline Resolution */} {settings.resolution === "timeline" && (
x
)} {/* Use vertical resolution */}
onSettingsChange({ useVerticalResolution: checked as boolean })} />
{/* Частота кадров */}
{/* Главы по маркерам */}
onSettingsChange({ chaptersByMarkers: checked as boolean })} />
{/* Использовать постоянный битрейт (только для H.264/H.265) */} {settings.format !== OutputFormat.Mov && (
onSettingsChange({ bitrateMode: checked ? "limit" : "auto" })} />
)} {/* Качество */}
onSettingsChange({ bitrateMode: v as any })} >
onSettingsChange({ bitrate: Number.parseInt(e.target.value) })} className="w-24" disabled={settings.bitrateMode === "auto"} /> Kbps
{t("dialogs.export.limitSpeed")} {t("dialogs.export.seconds")}
{/* Оптимизация для скорости */}
onSettingsChange({ optimizeForSpeed: checked as boolean })} />
{/* Профиль кодирования (только для H.264/H.265) */} {settings.format !== OutputFormat.Mov && (
)} {/* Режим энтропии (только для H.264) */} {settings.format === OutputFormat.Mp4 && settings.encodingProfile !== "main10" && (
)} {/* Чекбокс многократное кодирование */}
onSettingsChange({ multipassEncoding: checked as boolean })} />
{/* Ключевые кадры */}
onSettingsChange({ keyframeMode: v as "auto" | "every" })} >
onSettingsChange({ keyframeInterval: Number.parseInt(e.target.value) })} className="w-16" disabled={settings.keyframeMode === "auto"} /> {t("dialogs.export.frames")}
{/* Реорганизация кадров */}
onSettingsChange({ frameReordering: checked as boolean })} />
{/* Checkbox Экспорт аудио */}
onSettingsChange({ exportAudio: checked as boolean })} />
{/* Аудио настройки */}
{/* Normalize Audio */}
onSettingsChange({ normalizeAudio: checked as boolean })} />
{settings.normalizeAudio && (
{}}>
onSettingsChange({ audioTarget: Number(e.target.value) })} className="w-20" /> dBTP
onSettingsChange({ audioTarget: Number(e.target.value) })} className="w-20" /> LKFS
)}
{/* Вставка информации */}
{/* Чекбоксы для файла */}
onSettingsChange({ useProxyMedia: checked as boolean })} />
onSettingsChange({ renderWithoutTimecode: checked as boolean })} />
{/* Аппаратное ускорение */}
onSettingsChange({ enableGPU: checked as boolean })} />
{/* Вкладка переходов */}
{/* Расширенные настройки */}
{t("dialogs.export.advancedDescription")}
{/* Настройки субтитров */}
{t("dialogs.export.subtitlesDescription")}
{/* Progress and Export Button */}
{isRendering && renderProgress && (
{t("dialogs.export.progress")} {Math.round(renderProgress.percentage)}%
{renderProgress.message || t("dialogs.export.rendering")}
)}
{isRendering ? ( <> ) : ( <> )}
) }