import { useRef, useState, useCallback } from 'react' import { Play, Pause, Volume2, VolumeX, SkipBack, SkipForward, Maximize2, Minimize2, ListMusic, X } from 'lucide-react' import { usePlayerStore } from '@/stores/player' import { formatDuration } from '@/lib/utils' import { publicUrl } from '@/lib/storage' import { Avatar } from '@/components/ui/Avatar' import { isExternalUrl, getEmbedInfo } from '@/lib/embed' export function PlayerBar() { const { current, isPlaying, isExternal, progress, duration, volume, toggle, seek, setVolume, playbackRate, cyclePlaybackRate, queue, removeFromQueue, clearQueue, playNext, play } = usePlayerStore() const seekRef = useRef(null) const [isDragging, setIsDragging] = useState(false) const [dragPct, setDragPct] = useState(0) const [ytExpanded, setYtExpanded] = useState(false) const [queueOpen, setQueueOpen] = useState(false) const calcPct = useCallback((clientX: number) => { if (!seekRef.current) return 0 const rect = seekRef.current.getBoundingClientRect() return Math.max(0, Math.min(100, ((clientX - rect.left) / rect.width) * 100)) }, []) if (!current) return null const embedInfo = isExternal && current ? getEmbedInfo(current.audio_url) : null const isYouTube = embedInfo?.platform === 'youtube' const isSpotify = embedInfo?.platform === 'spotify' const chapters = current?.chapters || [] // Use store duration, fallback to podcast metadata duration const effectiveDuration = duration > 0 ? duration : (current?.duration_seconds || 0) const currentChapter = chapters.length > 0 && effectiveDuration > 0 ? [...chapters].reverse().find((ch) => progress >= ch.start_time_seconds) : null const pct = effectiveDuration > 0 ? (progress / effectiveDuration) * 100 : 0 const displayPct = isDragging ? dragPct : pct // Allow seeking for native audio and YouTube (via IFrame API) const canSeek = effectiveDuration > 0 const showBar = true function startDrag(clientX: number) { if (!canSeek) return setIsDragging(true) setDragPct(calcPct(clientX)) } function handleMouseDown(e: React.MouseEvent) { if (!canSeek) return e.preventDefault() startDrag(e.clientX) const onMove = (ev: MouseEvent) => setDragPct(calcPct(ev.clientX)) const onUp = (ev: MouseEvent) => { setIsDragging(false) const p = calcPct(ev.clientX) seek((p / 100) * effectiveDuration) window.removeEventListener('mousemove', onMove) window.removeEventListener('mouseup', onUp) } window.addEventListener('mousemove', onMove) window.addEventListener('mouseup', onUp) } function handleTouchStart(e: React.TouchEvent) { if (!canSeek) return startDrag(e.touches[0].clientX) const el = seekRef.current! const onMove = (ev: TouchEvent) => { ev.preventDefault(); setDragPct(calcPct(ev.touches[0].clientX)) } const onEnd = (ev: TouchEvent) => { setIsDragging(false) seek((calcPct(ev.changedTouches[0].clientX) / 100) * effectiveDuration) el.removeEventListener('touchmove', onMove) el.removeEventListener('touchend', onEnd) } el.addEventListener('touchmove', onMove, { passive: false }) el.addEventListener('touchend', onEnd) } function handleClick(e: React.MouseEvent) { if (!canSeek || isDragging) return seek((calcPct(e.clientX) / 100) * effectiveDuration) } const currentTime = isDragging ? (dragPct / 100) * effectiveDuration : progress return ( <> {/* YouTube player - mini or expanded */} {isYouTube && (
{/* Gradient overlay to hide YouTube title bar */}
)} {/* Spotify player - mini floating */} {isSpotify && embedInfo && (