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}