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}