spotdl-api
v1.0.0
Published
A powerful spotDL wrapper for Node.js to search, download, and sync Spotify tracks, albums, and playlists.
Maintainers
Readme
spotdl-api
A robust, fully-typed Node.js wrapper for spotdl (spotDL).
This package automatically downloads and manages the correct standalone spotdl executable for the host operating system during installation. It eliminates the need for a global Python or spotDL/ffmpeg dependency chain (ffmpeg is still required at runtime for audio conversion).
Installation
npm install spotdl-apiUsage Guide
The API is fully Promise-based and returns strictly typed objects.
1. Fetching Track/Album/Playlist Metadata
The save method resolves any spotdl query — a track, album, playlist, or artist URL, or free-text search — into full song metadata without downloading anything.
import spotdl from 'spotdl-api';
async function fetchMetadata() {
const songs = await spotdl.save('https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC');
console.log(songs[0].name); // Never Gonna Give You Up
console.log(songs[0].artists); // ['Rick Astley']
console.log(songs[0].duration); // 213
}JSON Output Structure Example:
{
"name": "Never Gonna Give You Up",
"artists": ["Rick Astley"],
"artist": "Rick Astley",
"album_name": "Whenever You Need Somebody",
"duration": 213,
"year": 1987,
"track_number": 1,
"song_id": "4uLU6hMCjMI75M1A2tKUQC",
"isrc": "GBARL9300135",
"cover_url": "https://i.scdn.co/image/...",
"url": "https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC"
}2. Looking Up a Single Song
getSongInfo is a convenience wrapper around save for a single query, returning just the first match.
import spotdl from 'spotdl-api';
const song = await spotdl.getSongInfo('The Weeknd - Blinding Lights');
console.log(song?.album_name);3. Downloading Tracks with Progress Tracking
The download method downloads and transcodes audio, providing real-time progress callbacks for every song in the query.
import spotdl from 'spotdl-api';
async function downloadTrack() {
await spotdl.download(
'https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC',
(progress) => {
// Example: { song: 'Rick Astley - Never Gonna Give You Up', message: 'Downloading', percent: 70, status: 'downloading' }
console.log(`${progress.song}: ${progress.message} (${progress.percent}%)`);
},
{ format: 'mp3', output: '{artists} - {title}.{output-ext}' }
);
}4. Downloading Albums and Playlists
Any query type — track, album, playlist, or artist URL — works the same way, and can be mixed in a single call.
import spotdl from 'spotdl-api';
await spotdl.download([
'https://open.spotify.com/playlist/37i9dQZF1E8UXBoz02kGID',
'The Weeknd - Blinding Lights',
]);5. Global Options (authentication, providers, cookies)
Pass a second argument to the SpotDl constructor to apply options to every call automatically — no need to repeat them via args each time.
import { SpotDl } from 'spotdl-api';
const spotdl = new SpotDl(undefined, {
clientId: 'your-spotify-client-id', // optional: spotDL ships public demo credentials by default
clientSecret: 'your-spotify-client-secret',
cookieFile: './cookies.txt', // enables higher-bitrate YouTube Music audio
audioProviders: ['youtube-music'],
lyricsProviders: ['genius', 'musixmatch'],
threads: 4,
restrict: 'ascii', // sanitize output filenames
});6. Resolving Direct Audio-Provider URLs
Skip the download entirely and get the raw, playable audio URL(s) resolved from the configured audio provider — useful for proxying or handing off to a media player.
import spotdl from 'spotdl-api';
const urls = await spotdl.getDirectUrl('https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC');
console.log(urls[0]); // https://...7. Typed Errors
Failures are classified into specific error subclasses so callers can branch on why spotdl failed instead of parsing stderr themselves.
import spotdl, { NoResultsFoundError, SpotifyAuthError, FFmpegNotFoundError, NetworkError } from 'spotdl-api';
try {
await spotdl.getSongInfo('some obscure query');
} catch (err) {
if (err instanceof NoResultsFoundError) {
// skip and move on
} else if (err instanceof NetworkError) {
// retry later
}
throw err;
}8. Syncing a Local Folder to a Playlist
createSyncFile snapshots a query into a .spotdl file; sync then downloads new songs and removes ones no longer present in the source, keeping a local folder mirrored to a playlist or album over time.
import spotdl from 'spotdl-api';
await spotdl.createSyncFile(
'https://open.spotify.com/playlist/37i9dQZF1E8UXBoz02kGID',
'./my-playlist.sync.spotdl'
);
// later, on a schedule:
await spotdl.sync('./my-playlist.sync.spotdl', (progress) => {
console.log(`${progress.song}: ${progress.message}`);
});9. Re-embedding Metadata
Refresh tags, cover art, and lyrics on already-downloaded files without re-downloading them.
import spotdl from 'spotdl-api';
await spotdl.embedMetadata(['./Rick Astley - Never Gonna Give You Up.mp3']);10. Cancelling In-Flight Requests
Every method that spawns spotdl accepts an AbortSignal via options.signal.
import spotdl from 'spotdl-api';
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
await spotdl.download(url, undefined, { signal: controller.signal });11. Batch Metadata Lookups with Bounded Concurrency
Fetches metadata for many queries at once without spawning unlimited processes. Each query resolves independently — one failure doesn't sink the batch.
import spotdl from 'spotdl-api';
const results = await spotdl.batchSave(queries, { concurrency: 3, delayMs: 250 });
for (const r of results) {
if (r.status === 'fulfilled') console.log(r.query, r.value[0]?.name);
else console.warn(r.query, r.reason.message);
}API Reference
new SpotDl(binaryPath?: string, globalOptions?: GlobalOptions)Creates a wrapper instance.globalOptions(Spotify auth, audio/lyrics providers, etc.) apply to every call made through it.spotdl.version(): Promise<string>Returns the version string of the underlyingspotdlbinary.spotdl.save(queries: string | string[], options?: SaveOptions): Promise<Song[]>Resolves one or more queries into full track metadata (spotdl save --save-file -). A single query can expand into many songs (album/playlist/artist).spotdl.getSongInfo(query: string, options?: SearchOptions): Promise<Song | undefined>Convenience wrapper aroundsavefor a single query, returning its first match.spotdl.getDirectUrl(queries: string | string[], options?: SpotDlOptions): Promise<string[]>Resolves the direct, playable audio-provider URL(s) for one or more queries without downloading.spotdl.download(queries: string | string[], onProgress?: (progress: DownloadProgress) => void, options?: DownloadOptions): Promise<void>Downloads and transcodes audio for one or more queries, emitting per-song progress events.spotdl.createSyncFile(queries: string | string[], saveFile: string, options?: DownloadOptions): Promise<void>Creates a.spotdlsync file for the given query, ready to be passed tosync.spotdl.sync(saveFile: string, onProgress?: (progress: DownloadProgress) => void, options?: SyncOptions): Promise<void>Downloads new songs and removes stale ones to keep a local folder in sync with a.spotdlfile.spotdl.embedMetadata(files: string[], options?: SpotDlOptions): Promise<void>Re-embeds metadata into already-downloaded audio files (spotdl meta).spotdl.batchSave(queries: string[], options?: BatchOptions): Promise<BatchResult<Song[]>[]>Runssaveover many queries with bounded concurrency; each query resolves independently as fulfilled or rejected.spotdl.exec(args: string[], signal?: AbortSignal): Promise<string>Executesspotdlwith arbitrary arguments and returns raw stdout.
License
MIT
