"use client"; import { Disc3, Music, Play, SkipForward, Square, Volume2 } from "lucide-react"; import Image from "next/image"; import { useCallback, useState } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Slider } from "@/components/ui/slider"; import { useMediaQueue, useMediaSkip, useMediaState, useMediaStop, useMediaVolume, useMediaWsSync, } from "@/hooks"; import type { WsHook } from "@/lib/ws-hook"; interface MusicPlayerProps { ws: WsHook; } export function MusicPlayer({ ws }: MusicPlayerProps) { const { data: mediaState } = useMediaState(); const queueMut = useMediaQueue(); const skipMut = useMediaSkip(); const stopMut = useMediaStop(); const volumeMut = useMediaVolume(); const [queueUrl, setQueueUrl] = useState(""); // Sync WS media_state into the query cache useMediaWsSync(ws); const handleQueue = useCallback(() => { if (!queueUrl.trim()) return; queueMut.mutate(queueUrl.trim()); setQueueUrl(""); }, [queueUrl, queueMut]); const handleVolume = useCallback( (value: number | readonly number[]) => { const vol = Array.isArray(value) ? value[0] : value; volumeMut.mutate(vol); }, [volumeMut], ); return ( Music Player
setQueueUrl(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleQueue()} className="flex-1 h-9" />
{mediaState?.current ? (

Now Playing

{mediaState.current.thumbnailUrl && ( )}

{mediaState.current.title ?? mediaState.current.source}

{mediaState.current.durationMs ? `${Math.floor(mediaState.current.durationMs / 60000)}:${String(Math.floor((mediaState.current.durationMs % 60000) / 1000)).padStart(2, "0")}` : "Live"}

) : ( !mediaState?.queue?.length && (

No media queued. Paste a URL above to start playing.

) )}
{mediaState && mediaState.queue.length > 0 && (

Queue ({mediaState.queue.length})

{mediaState.queue.map((item, i) => (
{i + 1}. {item.title ?? item.source}
))}
)}
); }