"use client"; import { useState, useCallback } from "react"; import { motion } from "framer-motion"; import { Video, Settings } from "lucide-react"; import { FileUploader } from "@/components/tools/FileUploader"; import { ProgressBar } from "@/components/tools/ProgressBar"; import { ResultPreview } from "@/components/tools/ResultPreview"; import { ConfigPanel, type ConfigOption } from "@/components/tools/ConfigPanel"; import { Button } from "@/components/ui/button"; import { useUploadStore } from "@/store/uploadStore"; import { generateId } from "@/lib/utils"; import type { UploadedFile, ProcessedFile, VideoFramesConfig } from "@/types"; const videoAccept = { "video/*": [".mp4", ".mov", ".avi", ".webm", ".mkv"], }; const defaultConfig: VideoFramesConfig = { fps: 30, format: "png", quality: 90, width: undefined, height: undefined, }; const configOptions: ConfigOption[] = [ { id: "fps", type: "slider", label: "Frame Rate", description: "Number of frames to extract per second", value: defaultConfig.fps, min: 1, max: 60, step: 1, suffix: " fps", icon: , }, { id: "format", type: "select", label: "Output Format", description: "Image format for the extracted frames", value: defaultConfig.format, options: [ { label: "PNG", value: "png" }, { label: "JPEG", value: "jpeg" }, { label: "WebP", value: "webp" }, ], }, { id: "quality", type: "slider", label: "Quality", description: "Image quality (for JPEG and WebP)", value: defaultConfig.quality, min: 1, max: 100, step: 1, suffix: "%", }, ]; export default function VideoFramesPage() { const { files, addFile, removeFile, clearFiles, processingStatus, setProcessingStatus } = useUploadStore(); const [config, setConfig] = useState(defaultConfig); const [processedFiles, setProcessedFiles] = useState([]); const handleFilesDrop = useCallback( (acceptedFiles: File[]) => { const newFiles: UploadedFile[] = acceptedFiles.map((file) => ({ id: generateId(), file, name: file.name, size: file.size, type: file.type, uploadedAt: new Date(), })); newFiles.forEach((file) => addFile(file)); }, [addFile] ); const handleConfigChange = (id: string, value: any) => { setConfig((prev) => ({ ...prev, [id]: value })); }; const handleResetConfig = () => { setConfig(defaultConfig); }; const handleProcess = async () => { if (files.length === 0) return; setProcessingStatus({ status: "uploading", progress: 0, message: "Uploading video...", }); try { // Simulate upload for (let i = 0; i <= 100; i += 10) { await new Promise((resolve) => setTimeout(resolve, 100)); setProcessingStatus({ status: "uploading", progress: i, message: `Uploading... ${i}%`, }); } setProcessingStatus({ status: "processing", progress: 0, message: "Extracting frames...", }); // Simulate processing for (let i = 0; i <= 100; i += 5) { await new Promise((resolve) => setTimeout(resolve, 150)); setProcessingStatus({ status: "processing", progress: i, message: `Processing... ${i}%`, }); } // Simulate completion const results: ProcessedFile[] = files.map((file) => ({ id: generateId(), originalFile: file, processedUrl: "#", metadata: { format: config.format, quality: config.quality, fps: config.fps, frames: Math.floor(10 * config.fps), // Simulated }, createdAt: new Date(), })); setProcessedFiles(results); clearFiles(); setProcessingStatus({ status: "completed", progress: 100, message: "Processing complete!", }); } catch (error) { setProcessingStatus({ status: "failed", progress: 0, message: "Processing failed", error: error instanceof Error ? error.message : "Unknown error", }); } }; const handleDownload = (fileId: string) => { console.log("Downloading file:", fileId); // Implement download logic }; const canProcess = files.length > 0 && processingStatus.status !== "processing"; return ( {/* Header */} Video to Frames Extract frames from videos with customizable settings {/* Left Column - Upload and Config */} ({ ...opt, value: config[opt.id as keyof VideoFramesConfig], }))} onChange={handleConfigChange} onReset={handleResetConfig} /> {canProcess && ( Process Video )} {/* Right Column - Progress and Results */} {processingStatus.status !== "idle" && ( )} {processedFiles.length > 0 && ( )} {/* Info Card */} How it works 1. Upload your video file (MP4, MOV, AVI, etc.) 2. Configure frame rate, format, and quality 3. Click "Process Video" to start extraction 4. Download the ZIP file with all frames ); }
Extract frames from videos with customizable settings