Last active
July 14, 2025 00:49
-
-
Save ritmo-v0/a847d54c3e2637df25416713b85ea3ab to your computer and use it in GitHub Desktop.
A simple TypeScript example of Spotify's `search` Web API.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { readFile } from "fs/promises"; | |
| // Types & Interfaces | |
| type Song = SongData & { | |
| search_result: SearchResult[]; | |
| }; | |
| type SongData = { | |
| name: string; | |
| artist: string; | |
| }; | |
| // # Modify based on your needs | |
| type SearchResult = Omit<TrackItem, "type" | "artists" | "duration_ms" | "external_urls"> & { | |
| artists: Array<string>; | |
| }; | |
| // # Add more keys based on your needs | |
| // Reference: https://developer.spotify.com/documentation/web-api/reference/search | |
| type SpotifySearchResponse = { | |
| tracks: { | |
| items: Array<TrackItem>; | |
| } | |
| }; | |
| type TrackItem = { | |
| id: string; | |
| name: string; | |
| type: "track"; | |
| artists: Array<SimplifiedArtist>; | |
| uri: string; | |
| href: string; | |
| duration_ms: number; | |
| external_urls: Record<string, string>; | |
| }; | |
| type SimplifiedArtist = { | |
| id: string; | |
| name: string; | |
| type: "artist"; | |
| uri: string; | |
| href: string; | |
| external_urls: Record<string, string>; | |
| }; | |
| type SearchOptions = { | |
| limit?: number; | |
| }; | |
| // Constants & Variables | |
| // ! Plz make sure to load secrets from .env* files other than local usage | |
| const CLIENT_ID = "YOUR_SPOTIFY_CLIENT_ID"; | |
| const CLIENT_SECRET = "YOUR_SPOTIFY_CLIENT_SECRET"; | |
| const BEARER_TOKEN = "YOUR_BEARER_TOKEN_FROM_getAccessToken"; | |
| // Request an Access Token | |
| // Reference: https://developer.spotify.com/documentation/web-api/tutorials/getting-started#request-an-access-token | |
| async function getAccessToken() { | |
| const token = await fetch("https://accounts.spotify.com/api/token", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/x-www-form-urlencoded" }, | |
| body: new URLSearchParams({ | |
| grant_type: "client_credentials", | |
| client_id: CLIENT_ID, | |
| client_secret: CLIENT_SECRET, | |
| }) | |
| }).then(res => res.json()); | |
| return token.access_token; | |
| } | |
| // # Write your own data loading logic here | |
| async function getSongData(): Promise<Record<string, SongData>> { | |
| const data = await readFile("RITMOS_SECRET_LIBRARY.json", "utf8"); | |
| return JSON.parse(data); | |
| } | |
| // Fetch result from `Search` Web API | |
| // ! You might consider adding a delay between (batch) searches to avoid 429s | |
| async function fetchSongSearchResult(song: SongData, { | |
| limit = 3, | |
| }: SearchOptions = {}): Promise<Array<TrackItem>> { | |
| const name = song.name; | |
| const artist = song.artist; | |
| const fetchURL = "https://api.spotify.com/v1/search?" + new URLSearchParams({ | |
| q: `track:${name} artist:${artist}`, | |
| type: "track", | |
| limit: String(limit), | |
| }).toString(); | |
| const res = await fetch(fetchURL, { | |
| headers: { "Authorization": `Bearer ${BEARER_TOKEN}` }, | |
| }); | |
| if (!res.ok) throw new Error(`HTTP ${res.status} - ${res.statusText}`); | |
| const data: SpotifySearchResponse = await res.json(); | |
| return data.tracks.items; | |
| } | |
| // # Example Usage | |
| // In this example, I have the order No. from "Ritmo's Secret Library" as the key of each SongData object, | |
| // hence the return type `Record<string, SongData>` of `getSongData()`. | |
| try { | |
| const songs = await getSongData(); | |
| for (const [order, song] of Object.entries(songs)) { | |
| console.log(`🔍 Searching for song ${order.padStart(3, "0")}: ${song.name} / ${song.artist}...`); | |
| const trackItems = await fetchSongSearchResult(song); | |
| const fullSongData: Song = { | |
| ...song, | |
| search_result: trackItems.map(item => ({ | |
| id: item.id, | |
| name: item.name, | |
| artists: item.artists.map(artist => artist.name), | |
| uri: item.uri, | |
| href: item.external_urls.spotify, | |
| })), | |
| }; | |
| console.log(`${JSON.stringify(fullSongData, null, 2)}\n`); | |
| } | |
| } catch (error) { | |
| console.error("ERR:", error); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment