/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { ExternalLink, Copy } from 'lucide-react' import { useState, useRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { Button } from '@/components/design-system/button' import { StatusBadge } from '@/components/status-badge' export interface AudioClip { clip_id?: string id?: string title?: string tags?: string duration?: number audio_url?: string image_url?: string image_large_url?: string metadata?: { tags?: string duration?: number } } function formatDuration(seconds?: number): string { if (!seconds || seconds <= 0) return '--:--' const m = Math.floor(seconds / 60) const s = Math.floor(seconds % 60) return `${m}:${s.toString().padStart(2, '0')}` } export function AudioClipCard({ clip }: { clip: AudioClip }) { const { t } = useTranslation() const [hasError, setHasError] = useState(false) const audioRef = useRef(null) useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setHasError(false) }, [clip.audio_url]) const title = clip.title || t('Untitled') const tags = clip.tags || clip.metadata?.tags || '' const duration = clip.duration || clip.metadata?.duration const imageUrl = clip.image_url || clip.image_large_url const audioUrl = clip.audio_url if (!audioUrl) return null return (
{imageUrl && ( {title} { ;(e.target as HTMLElement).style.display = 'none' }} /> )}
{title} {duration != null && duration > 0 && ( {formatDuration(duration)} )}
{tags && (

{tags}

)} {hasError ? (
{t('Audio playback failed')}
) : (
) }