My personal site hosted @ https://indexx.dev
1import { useEffect, useState } from "react";
2import AudioVisualizer from "./AudioVisualizer";
3
4export default function Lastfm() {
5 const [data, setData] = useState(null);
6 const [error, setError] = useState(null);
7
8 useEffect(() => {
9 const fetchLastfmData = async () => {
10 try {
11 const res = await fetch(
12 "https://workers.indexx.dev/misc/lastfm",
13 );
14 if (!res.ok) throw new Error(`HTTP ${res.status}`);
15
16 const json = await res.json();
17 const status = {
18 song: json.track,
19 artist: json.artist,
20 albumArt: json.cover,
21 createdAt: json.createdAt,
22 link: json.url,
23 nowPlaying: !json.createdAt,
24 };
25 setData(status);
26 } catch (err) {
27 console.error("Fetch failed:", err);
28 setError(err.message);
29 }
30 };
31
32 fetchLastfmData();
33 }, []);
34
35 if (error || !data) return null;
36
37 let timeAgo = "";
38 let oldStatusClasses = "";
39
40 if (!data.nowPlaying && data.createdAt) {
41 const date = new Date(data.createdAt);
42 const now = new Date();
43 const diff = now.getTime() - date.getTime();
44
45 const minutes = Math.floor(diff / 60000);
46 const hours = Math.floor(minutes / 60);
47 const days = Math.floor(hours / 24);
48
49 if (days > 0) timeAgo = `${days} days ago`;
50 else if (hours > 0) timeAgo = `${hours} hours ago`;
51 else if (minutes > 0) timeAgo = `${minutes} minutes ago`;
52 else timeAgo = "just now";
53
54 if (days == 1) timeAgo = "1 day ago";
55
56 oldStatusClasses = days > 3
57 ? "opacity-75 text-decoration-line-through"
58 : "";
59 }
60
61 return (
62 <a
63 id="now-playing"
64 href={data.link}
65 target="_blank"
66 className={oldStatusClasses}
67 >
68 <AudioVisualizer isSilent={!data.nowPlaying} />
69 <div
70 style={{
71 display: "flex",
72 flexDirection: "column",
73 gap: "2px",
74 width: "100%",
75 }}
76 >
77 <div style={{ fontWeight: "bold" }}>{data.song}</div>
78 <div style={{ fontSize: "0.9em", marginTop: "-5px" }}>
79 {data.artist}
80 </div>
81 <div
82 style={{
83 fontSize: "0.8em",
84 opacity: 0.7,
85 marginTop: "-5px",
86 }}
87 >
88 <small style={{ fontSize: "0.7rem" }}>
89 ^ what I'm listening (or last listened) to
90 </small>
91 </div>
92 </div>
93 </a>
94 );
95}