Spotify data parsing example. Typebulb gives the AI assistant a summarized view of the data tab. This ensures the AI sees the structure of the data without wasting its context window. AIs are inc...
import React from "react";
import { createRoot } from "react-dom/client"
interface SpotifyArtist {
name: string;
external_urls: { spotify: string };
}
interface SpotifyImage {
url: string;
height: number;
width: number;
}
interface SpotifyTrack {
id: string;
name: string;
track_number: number;
duration_ms: number;
explicit: boolean;
artists: SpotifyArtist[];
}
interface SpotifyAlbum {
name: string;
album_type: string;
release_date: string;
total_tracks: number;
images: SpotifyImage[];
artists: SpotifyArtist[];
tracks: {
items: SpotifyTrack[];
};
}
function formatDuration(ms: number) {
const minutes = Math.floor(ms / 60000);
const seconds = ((ms % 60000) / 1000).toFixed(0);
return `${minutes}:${Number(seconds) < 10 ? '0' : ''}${seconds}`;
}
function App() {
const data = React.useMemo(() => {
try {
return tb.json<SpotifyAlbum>(0);
} catch (e) {
console.error("Failed to parse data", e);
return null;
}
}, []);
if (!data) {
return <div className="container">Error loading album data.</div>;
}
const mainArtist = data.artists[0];
const coverArt = data.images[0]?.url;
const releaseYear = new Date(data.release_date).getFullYear();
return (
<div className="container">
<header className="album-header">
<img src={coverArt} alt={data.name} className="album-art" />
<div className="album-info">
<div className="album-meta" style={{ textTransform: 'uppercase', fontSize: '0.75rem', marginBottom: '0.5rem' }}>
{data.album_type}
</div>
<h1>{data.name}</h1>
<div className="album-meta">
<a href={mainArtist.external_urls.spotify} className="artist-link" target="_blank" rel="noreferrer">
{mainArtist.name}
</a>
<span className="meta-separator">{releaseYear}</span>
<span className="meta-separator">{data.total_tracks} songs</span>
</div>
</div>
</header>
<div className="tracklist">
{data.tracks.items.map((track) => (
<div key={track.id} className="track-item">
<div className="track-number">{track.track_number}</div>
<div className="track-main">
<div className="track-name">
{track.name}
{track.explicit && <span className="explicit-badge">E</span>}
</div>
<div className="track-artist">
{track.artists.map(a => a.name).join(", ")}
</div>
</div>
<div className="track-duration">
{formatDuration(track.duration_ms)}
</div>
</div>
))}
</div>
</div>
);
}
const container = document.getElementById("root")
const root = createRoot(container!)
root.render(<App />)