import { AppLayout } from '@/components/AppLayout' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { type ExtractionInfo, extractionsService, } from '@/lib/api/services/extractions' import { formatDateDistanceToNow } from '@/utils/format-date' import { AlertCircle, Calendar, CheckCircle, Clock, Download, ExternalLink, Loader2, Plus, } from 'lucide-react' import { useEffect, useState } from 'react' import { toast } from 'sonner' export function ExtractionsPage() { const [extractions, setExtractions] = useState([]) const [isLoading, setIsLoading] = useState(true) const [isDialogOpen, setIsDialogOpen] = useState(false) const [url, setUrl] = useState('') const [isCreating, setIsCreating] = useState(false) // Load extractions const loadExtractions = async () => { try { setIsLoading(true) const data = await extractionsService.getUserExtractions() setExtractions(data) } catch (error) { console.error('Failed to load extractions:', error) toast.error('Failed to load extractions') } finally { setIsLoading(false) } } useEffect(() => { loadExtractions() }, []) // Create new extraction const handleCreateExtraction = async () => { if (!url.trim()) { toast.error('Please enter a URL') return } try { setIsCreating(true) const response = await extractionsService.createExtraction(url.trim()) toast.success(response.message) setUrl('') setIsDialogOpen(false) // Refresh the list await loadExtractions() } catch (error) { console.error('Failed to create extraction:', error) toast.error('Failed to create extraction') } finally { setIsCreating(false) } } const getStatusBadge = (status: ExtractionInfo['status']) => { switch (status) { case 'pending': return ( Pending ) case 'processing': return ( Processing ) case 'completed': return ( Completed ) case 'failed': return ( Failed ) } } const getServiceBadge = (service: string | undefined) => { if (!service) return null const serviceColors: Record = { youtube: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300', soundcloud: 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300', vimeo: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300', tiktok: 'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300', twitter: 'bg-sky-100 text-sky-800 dark:bg-sky-900 dark:text-sky-300', instagram: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300', } const colorClass = serviceColors[service.toLowerCase()] || 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300' return ( {service.toUpperCase()} ) } return (

Audio Extractions

Extract audio from YouTube, SoundCloud, and other platforms

Create New Extraction
setUrl(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && !isCreating) { handleCreateExtraction() } }} />

Supports YouTube, SoundCloud, Vimeo, TikTok, Twitter, Instagram, and more

{isLoading ? (
Loading extractions...
) : extractions.length === 0 ? (

No extractions yet

Start by adding a URL to extract audio from your favorite platforms

) : ( Recent Extractions ({extractions.length}) Title Service Status Created Actions {extractions.map(extraction => (
{extraction.title || 'Extracting...'}
{extraction.url}
{getServiceBadge(extraction.service)} {getStatusBadge(extraction.status)} {extraction.error && (
{extraction.error}
)}
{formatDateDistanceToNow(extraction.created_at)}
))}
)}
) }