import { useLocation } from 'react-router-dom'; import { useEffect, useRef, useState } from "react"; import Playbar from "./../components/video/Playbar"; import PlaybackSlider from "./../components/video/PlaybackSlider"; import ClipRangeSlider from "./../components/video/ClipRangeSlider"; import ConfigBox from "../components/video/ConfigBox.tsx"; import ExportWidget from "../components/video/ExportWidget.tsx"; import { compress } from "../utils/api/media" import { getJob } from "../utils/api/jobs" import type { VideoMetadata } from "../utils/types.ts"; import Box from "../components/Box.tsx"; import MetadataBox from "../components/video/MetadataBox.tsx"; const API_URL = import.meta.env.VITE_API_URL; const ClipEdit = () => { const location = useLocation(); const localFile: File = location.state?.file; const videoRef = useRef(null); const [videoUrl, setVideoUrl] = useState(''); const [uploadedId, setUploadedId] = useState(null); const [metadata, setMetadata] = useState(null); const [playbackValue, setPlaybackValue] = useState(0); const [outputMetadata, setOutputMetadata] = useState({ title: "", description: "", startPoint: 0, duration: 5, width: 1280, height: 720, fps: 30, fileSize: 10000 }); const [progress, setProgress] = useState(0); const [downloadable, setDownloadable] = useState(false); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (!localFile) return; const url = URL.createObjectURL(localFile); setVideoUrl(url); return () => URL.revokeObjectURL(url); }, [localFile]); const handleVideoMetadataLoaded = () => { const video = videoRef.current; if (!video) return; setMetadata({ title: '', description: '', startPoint: 0, duration: video.duration, width: video.videoWidth, height: video.videoHeight, fps: 30, fileSize: localFile?.size ?? 0, }); }; const sendData = async () => { if (!localFile || uploading) return; setUploading(true); setError(null); let jobId: string; try { jobId = await compress(localFile, outputMetadata); setUploadedId(jobId); } catch (err: unknown) { setError(`Failed to start compression: ${err instanceof Error ? err.message : 'Unknown error'}`); setUploading(false); return; } const interval = setInterval(async () => await pollProgress(jobId, interval), 500); }; const pollProgress = async (jobId: string, intervalId: number) => { getJob(jobId) .then((job) => { setProgress(job.progress); if (job.state === 'FAILED') { setError(`Compression failed: ${job.errorOutput ?? 'Unknown error'}`); clearInterval(intervalId); setUploading(false); } else if (job.isComplete) { clearInterval(intervalId); setDownloadable(true); setUploading(false); } }) .catch((err: Error) => { setError(`Failed to fetch progress: ${err.message}`); clearInterval(intervalId); setUploading(false); }); }; const handleDownload = async () => { if (!uploadedId) return; const response = await fetch(API_URL + `/api/v1/jobs/${uploadedId}/download`, { credentials: 'include' }); if (!response.ok) { console.error('Download failed'); return; } const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${uploadedId}.mp4`; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); }; return (
); }; export default ClipEdit;