"use client" import type React from "react" import { useEffect, useState, useCallback } from "react" import Image from "next/image" import { Loader2, AlertCircle } from "lucide-react" import { PiMusicNotesFill } from "react-icons/pi"; import { FaBluetoothB } from "react-icons/fa6"; import { IoBatteryFullSharp } from "react-icons/io5" import { IoIosPlay } from "react-icons/io" import { TbDiscOff } from "react-icons/tb" import { Progress } from "@/components/ui/progress" import Link from "@/components/objects/Link" import ScrollTxt from "@/components/objects/MusicText" interface Track { track_name: string artist_name: string release_name?: string mbid?: string } const NowPlaying: React.FC = () => { const [track, setTrack] = useState(null) const [coverArt, setCoverArt] = useState(null) const [loading, setLoading] = useState(true) const [loadingStatus, setLoadingStatus] = useState("Initializing") const [error, setError] = useState(null) const [progress, setProgress] = useState(0) const [steps, setSteps] = useState(0) const [currentTime, setCurrentTime] = useState(new Date()) const [volume, setVolume] = useState(25) const [screenOn, setScreenOn] = useState(true) const updateProgress = useCallback((current: number, total: number, status: string) => { setProgress(current) setSteps(total) setLoadingStatus(status) console.log(`[${current}/${total}] ${status}`) }, []) const fetchAlbumArt = useCallback(async (artist: string, album?: string) => { if (!album) { updateProgress(0, 0, "No album found") setCoverArt(null) setLoading(false) return } try { updateProgress(2, 3, `Searching for album: ${artist} - ${album}`) const response = await fetch( `https://musicbrainz.org/ws/2/release/?query=artist:${encodeURIComponent( artist )}%20AND%20release:${encodeURIComponent(album)}&fmt=json` ) if (!response.ok) { updateProgress(0, 0, `Album art fetch error: ${response.status}`) setError("Error fetching album art (see console for details)") setLoading(false) return } const data = await response.json() if (data.releases && data.releases.length > 0) { const mbid = data.releases[0].id updateProgress(3, 3, "Fetching cover art...") setTrack(prev => prev ? { ...prev, mbid: `${mbid || null}` } : { track_name: "", artist_name: "", release_name: undefined, mbid: `${mbid || null}` }) const coverArtResponse = await fetch(`https://coverartarchive.org/release/${mbid}/front`) if (coverArtResponse.ok) { setCoverArt(coverArtResponse.url) setLoading(false) } else { updateProgress(0, 0, "Cover art not found") setCoverArt(null) setLoading(false) } } else { updateProgress(0, 0, "No releases found") setCoverArt(null) setLoading(false) } } catch (error) { updateProgress(0, 0, `Error: ${error}`) setCoverArt(null) setLoading(false) } }, [updateProgress]) const fetchNowPlaying = useCallback(async () => { updateProgress(1, 3, "Fetching current listen...") try { const response = await fetch("https://api.listenbrainz.org/1/user/p0ntus/playing-now") const data = await response.json() if (data.payload.count > 0 && data.payload.listens[0].track_metadata) { const trackMetadata = data.payload.listens[0].track_metadata console.log("= TRACK METADATA =") if (trackMetadata.track_name) { console.log("🎵", trackMetadata.track_name) } if (trackMetadata.artist_name) { console.log("🎤", trackMetadata.artist_name) } if (trackMetadata.release_name) { console.log("💿", trackMetadata.release_name) } setTrack({ track_name: trackMetadata.track_name, artist_name: trackMetadata.artist_name, release_name: trackMetadata.release_name, mbid: trackMetadata.mbid, }) updateProgress(2, 3, "Finding album art...") await fetchAlbumArt(trackMetadata.artist_name, trackMetadata.release_name) } else { updateProgress(0, 0, "No track playing") setLoading(false) } } catch (error) { updateProgress(0, 0, `Error: ${error}`) setError("Error fetching now playing data") setLoading(false) } }, [fetchAlbumArt, updateProgress]) useEffect(() => { fetchNowPlaying() }, [fetchNowPlaying]) useEffect(() => { const timer = setInterval(() => { setCurrentTime(new Date()) }, 1000) return () => clearInterval(timer) }, []) const formatTime = (date: Date) => { return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }) } const renderScreenContent = () => { if (loading) { return (
{loadingStatus}
0 ? (progress * 100) / steps : 0} className="h-1" />
) } if (error) { return (
{error}
) } if (!track) { return (
Nothing playing
Check my ListenBrainz
) } // normal state const currentTrack = track!; return ( <>
{currentTrack.release_name && }
{/* Album art */}
{coverArt ? ( {currentTrack.track_name} ) : (
)}
{/* Player controls and seekbar */}
setVolume(Number(e.target.value))} className="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
) } return (
{/* Volume buttons */}
setVolume(v => Math.min(100, v + 5))}>
{/* up */}
{/* play/pause */}
setVolume(v => Math.max(0, v - 5))}>
{/* down */}
{/* Top power button */}
setScreenOn(prev => !prev)}>
{/* White bezel (fuses screen+home btn) */}
{/* Virtual screen */}
{screenOn && (
{formatTime(currentTime)}
)} {screenOn ? renderScreenContent() : (
)} {/* Player controls and seekbar */} {screenOn && track && (
setVolume(Number(e.target.value))} className="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
)}
{/* Home button */}
) } export default NowPlaying