My personal site hosted @ https://indexx.dev
1import { useEffect, useState } from "react"; 2 3export default function NowPlaying() { 4 const [data, setData] = useState(null); 5 const [error, setError] = useState(null); 6 7 useEffect(() => { 8 const fetchNowPlaying = async () => { 9 try { 10 const res = await fetch( 11 "https://lastfm-last-played.biancarosa.com.br/Index_Card/latest-song", 12 ); 13 if (!res.ok) throw new Error(`HTTP ${res.status}`); 14 15 const json = await res.json(); 16 const track = json.track; 17 const isNowPlaying = track["@attr"]?.nowplaying === "true"; 18 19 const status = { 20 song: track.name, 21 artist: track.artist["#text"], 22 album: track.album["#text"], 23 createdAt: track.date 24 ? new Date(track.date.uts * 1000).toISOString() 25 : null, 26 link: track.url, 27 nowPlaying: isNowPlaying, 28 albumArt: track.image.find((img) => 29 img.size === "medium" 30 )["#text"], 31 }; 32 setData(status); 33 } catch (err) { 34 console.error("Fetch failed:", err); 35 setError(err.message); 36 } 37 }; 38 39 fetchNowPlaying(); 40 }, []); 41 42 if (error) return <span>Error: {error}</span>; 43 if (!data) return <span>Loading now playing...</span>; 44 45 let timeAgo = ""; 46 let oldStatusClasses = ""; 47 48 if (!data.nowPlaying && data.createdAt) { 49 const date = new Date(data.createdAt); 50 const now = new Date(); 51 const diff = now.getTime() - date.getTime(); 52 53 const minutes = Math.floor(diff / 60000); 54 const hours = Math.floor(minutes / 60); 55 const days = Math.floor(hours / 24); 56 57 if (days > 0) timeAgo = `${days} days ago`; 58 else if (hours > 0) timeAgo = `${hours} hours ago`; 59 else if (minutes > 0) timeAgo = `${minutes} minutes ago`; 60 else timeAgo = "just now"; 61 62 oldStatusClasses = days > 3 63 ? "opacity-75 text-decoration-line-through" 64 : ""; 65 } 66 67 return ( 68 <a 69 href={data.link} 70 target="_blank" 71 style={{ 72 position: "fixed", 73 bottom: "20px", 74 left: "20px", 75 display: "flex", 76 alignItems: "center", 77 gap: "12px", 78 padding: "8px", 79 backgroundColor: "#1e1d2d", 80 borderRadius: "8px", 81 boxShadow: "0 2px 6px rgba(0, 0, 0, 0.1)", 82 textDecoration: "none", 83 color: "#000", 84 maxWidth: "400px", 85 transition: "opacity 0.2s", 86 textAlign: "left", 87 }} 88 className={oldStatusClasses} 89 > 90 <img 91 src={data.albumArt} 92 alt={`${data.album} cover`} 93 style={{ 94 width: "64px", 95 height: "64px", 96 borderRadius: "4px", 97 objectFit: "cover", 98 }} 99 /> 100 <div 101 style={{ 102 display: "flex", 103 flexDirection: "column", 104 gap: "2px", 105 }} 106 > 107 <div style={{ fontWeight: "bold" }}>{data.song}</div> 108 <div style={{ fontSize: "0.9em", marginTop: "-5px" }}> 109 {data.artist} 110 </div> 111 <div 112 style={{ 113 fontSize: "0.8em", 114 opacity: 0.7, 115 marginTop: "-5px", 116 }} 117 > 118 {data.nowPlaying 119 ? ( 120 <span style={{ color: "#22c55e" }}> 121 Now Playing 122 </span> 123 ) 124 : timeAgo} 125 </div> 126 </div> 127 </a> 128 ); 129}