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 (
);
}