import React, { useState, useEffect } from 'react'; import { Plus, Trash2, Save, Clock, PenLine, Volume2, XCircle } from 'lucide-react'; import { processApi } from '../api/client'; export default function ManualSubtitleInput({ job, onProcessWithSubtitle, onProcessWithoutSubtitle, onCancel }) { const [segments, setSegments] = useState([]); const [isSaving, setIsSaving] = useState(false); const [videoDuration, setVideoDuration] = useState(60); // Default 60 seconds // Initialize with one empty segment useEffect(() => { if (segments.length === 0) { addSegment(); } }, []); const addSegment = () => { const lastEnd = segments.length > 0 ? segments[segments.length - 1].end : 0; setSegments([ ...segments, { id: Date.now(), start: lastEnd, end: Math.min(lastEnd + 3, videoDuration), text: '', translated: '', }, ]); }; const removeSegment = (id) => { setSegments(segments.filter((seg) => seg.id !== id)); }; const updateSegment = (id, field, value) => { setSegments( segments.map((seg) => seg.id === id ? { ...seg, [field]: value } : seg ) ); }; const formatTimeInput = (seconds) => { const mins = Math.floor(seconds / 60); const secs = (seconds % 60).toFixed(1); return `${mins}:${secs.padStart(4, '0')}`; }; const parseTimeInput = (timeStr) => { const parts = timeStr.split(':'); if (parts.length === 2) { const mins = parseInt(parts[0]) || 0; const secs = parseFloat(parts[1]) || 0; return mins * 60 + secs; } return parseFloat(timeStr) || 0; }; const handleSaveSubtitles = async () => { // Validate segments const validSegments = segments.filter( (seg) => seg.text.trim() || seg.translated.trim() ); if (validSegments.length === 0) { alert('최소 한 개의 자막을 입력해주세요.'); return; } setIsSaving(true); try { // Format segments for API const formattedSegments = validSegments.map((seg) => ({ start: seg.start, end: seg.end, text: seg.text.trim() || seg.translated.trim(), translated: seg.translated.trim() || seg.text.trim(), })); await processApi.addManualSubtitle(job.job_id, formattedSegments); onProcessWithSubtitle?.(formattedSegments); } catch (err) { console.error('Failed to save subtitles:', err); alert('자막 저장 실패: ' + (err.response?.data?.detail || err.message)); } finally { setIsSaving(false); } }; const handleProcessWithoutSubtitle = () => { onProcessWithoutSubtitle?.(); }; return (

자막 직접 입력

{segments.length}개 세그먼트

영상에 표시할 자막을 직접 입력하세요. 시작/종료 시간과 텍스트를 설정합니다.

{/* Segments List */}
{segments.map((segment, index) => (
#{index + 1}
{/* Time Inputs */}
updateSegment(segment.id, 'start', parseFloat(e.target.value) || 0) } className="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm focus:outline-none focus:border-amber-500" />
updateSegment(segment.id, 'end', parseFloat(e.target.value) || 0) } className="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm focus:outline-none focus:border-amber-500" />
{/* Text Input */}