import { useState, useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; import { motion } from 'framer-motion'; import toast from 'react-hot-toast'; import { ingestUrl, ingestUpload, getSessionStatus } from '../api/client'; export default function VideoInput({ onVideoLoaded }) { const [url, setUrl] = useState(''); const [loading, setLoading] = useState(false); const [progress, setProgress] = useState(0); const [statusMessage, setStatusMessage] = useState(''); const handleUrlSubmit = async (e) => { e.preventDefault(); if (!url.trim()) return; setLoading(true); setStatusMessage('Starting download...'); try { const result = await ingestUrl(url.trim()); // Poll for download completion const sessionId = result.session_id; let attempts = 0; const maxAttempts = 120; // 10 minutes max const pollStatus = async () => { while (attempts < maxAttempts) { await new Promise(r => setTimeout(r, 5000)); attempts++; setProgress(Math.min(attempts * 2, 90)); try { const status = await getSessionStatus(sessionId); if (status.status === 'downloaded') { setProgress(100); setStatusMessage('Download complete!'); toast.success('Video downloaded successfully!'); onVideoLoaded(status); return; } else if (status.status === 'error') { throw new Error(status.error || 'Download failed'); } setStatusMessage(`Downloading... (${attempts * 5}s)`); } catch (err) { if (err.message !== 'Download failed') continue; throw err; } } throw new Error('Download timed out'); }; await pollStatus(); } catch (err) { toast.error(err.response?.data?.detail || err.message || 'Failed to download video'); setStatusMessage(''); } finally { setLoading(false); setProgress(0); } }; const onDrop = useCallback(async (acceptedFiles) => { const file = acceptedFiles[0]; if (!file) return; // Validate size if (file.size > 2 * 1024 * 1024 * 1024) { toast.error('File too large. Maximum size is 2GB.'); return; } setLoading(true); setStatusMessage('Uploading...'); try { const result = await ingestUpload(file, (percent) => { setProgress(percent); setStatusMessage(`Uploading... ${percent}%`); }); toast.success('Video uploaded successfully!'); onVideoLoaded(result); } catch (err) { toast.error(err.response?.data?.detail || 'Upload failed'); setStatusMessage(''); } finally { setLoading(false); setProgress(0); } }, [onVideoLoaded]); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accept: { 'video/*': ['.mp4', '.mov', '.mkv', '.avi', '.webm'] }, maxFiles: 1, disabled: loading, }); return (
{/* Hero */}
Turn Long Videos Into Viral Clips

Drop a video or paste a URL. We'll AI-generate multiple viral-ready short clips with voiceover, captions, sound effects, and more.

{/* URL Input */}

🔗 Paste Video URL

setUrl(e.target.value)} placeholder="https://youtube.com/watch?v=... or any video URL" className="flex-1 bg-dark-900 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-white/30 focus:outline-none focus:border-primary-500/50 transition-colors" disabled={loading} />

Supports YouTube, Vimeo, Twitter/X, and most public video URLs

{/* Divider */}
OR
{/* File Upload Dropzone */}
{isDragActive ? '📥' : '🎥'}

{isDragActive ? 'Drop it here!' : 'Drag & Drop Video File'}

or click to browse • MP4, MOV, MKV, AVI, WebM up to 2GB

📋 Requirements: 60 seconds – 3 hours duration
{/* Progress Bar */} {loading && (
{statusMessage} {progress}%
)}
); }