import { useSignal } from "@preact/signals"; import { useEffect } from "preact/hooks"; interface SpotifyTrack { name: string; artists: { name: string }[]; is_playing: boolean; external_urls?: { spotify: string; }; } interface SpotifyResponse { is_playing: boolean; item: SpotifyTrack; } interface SpotifyIconProps { profileUrl?: string; } // Spotify SVG icon component const SpotifySVG = ({ className }: { className?: string }) => ( ); export default function SpotifyIcon({ profileUrl = "https://open.spotify.com" }: SpotifyIconProps) { const currentTrack = useSignal(null); const isPlaying = useSignal(false); const isDynamicEnabled = useSignal(false); const hasLoggedError = useSignal(false); useEffect(() => { // First, check if Spotify is properly configured const checkConfiguration = async () => { try { const response = await fetch('/api/spotify/config'); if (!response.ok) { throw new Error(`Spotify config endpoint returned status ${response.status}`); } const { configured } = await response.json(); if (!configured) { if (!hasLoggedError.value) { console.warn('[Spotify] Dynamic features disabled: missing or invalid environment variables.'); hasLoggedError.value = true; } isDynamicEnabled.value = false; return; } isDynamicEnabled.value = true; initializeSpotifyConnection(); } catch (error: any) { if (!hasLoggedError.value) { console.error('[Spotify] Could not enable dynamic features:', error?.message || error); hasLoggedError.value = true; } isDynamicEnabled.value = false; } }; checkConfiguration(); }, []); const initializeSpotifyConnection = () => { // Set up Server-Sent Events connection const eventSource = new EventSource('/api/spotify/stream'); eventSource.onopen = () => { // Only log on first open if (!hasLoggedError.value) { console.info('[Spotify] SSE connected for dynamic icon.'); } }; eventSource.onmessage = (event) => { try { const data: SpotifyResponse = JSON.parse(event.data); if (data.is_playing && data.item) { currentTrack.value = data.item; isPlaying.value = data.is_playing; } else { currentTrack.value = null; isPlaying.value = false; } } catch (err) { if (!hasLoggedError.value) { console.error('[Spotify] Error parsing SSE data:', err); hasLoggedError.value = true; } // Fail silently - will revert to static mode } }; eventSource.onerror = (event) => { if (!hasLoggedError.value) { console.error('[Spotify] SSE connection error. Falling back to static icon.'); hasLoggedError.value = true; } // If SSE fails, we just fall back to static mode }; // Cleanup on unmount return () => { eventSource.close(); }; }; const getTooltipText = () => { if (isDynamicEnabled.value && currentTrack.value && isPlaying.value) { const artists = currentTrack.value.artists.map(artist => artist.name).join(', '); return `♪ ${currentTrack.value.name} by ${artists} (click to open in Spotify)`; } return "Spotify"; }; const getSpotifyUrl = () => { // If we have a current track with external URL, use that if (isDynamicEnabled.value && currentTrack.value && isPlaying.value && currentTrack.value.external_urls?.spotify) { return currentTrack.value.external_urls.spotify; } // Otherwise, use the provided profile URL or fallback to general Spotify return profileUrl; }; return (
{isDynamicEnabled.value && isPlaying.value && (
)}
); }