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