- TypeScript 100%
| lib | ffiiixxx | |
| .gitignore | remove axios, add support for cookie rotation | |
| LICENSE | Initial commit | |
| package-lock.json | remove axios, add support for cookie rotation | |
| package.json | hmmmm | |
| pnpm-lock.yaml | hmmmm | |
| pnpm-workspace.yaml | hmmmm | |
| README.md | add another example | |
| tsconfig.json | initial commit | |
s-dl
CLI-less port of glomatico/spotify-aac-downloader. Downloads AAC of the requested song straight from Spotify.
Why
This library was ported by me as a way to implement an actually accurate Spotify format/service for Discord voice bots, made in JavaScript. The rest Spotify downloader libraries suck, due to their general idea of downloading the audio from 3rd-party sources. Here is an example of how would a typical Spotify downloader work:
- Get the song's information on Spotify;
- Search the song on YouTube using this information;
- Download the song from YouTube.
It may work sometimes, but it also may lead into less-accurate results. For example, if the music video is popular instead of the actual song, it will most likely play the music video, which may contain music-video-specific intros, outros or any other inserts, that are not specific for the requested song.
Disclaimer
The way that this software is going to be used is up to the user and not to the author.
Prerequisites
You need to extract cookies from Spotify while being logged in.
You also need to extract Widevine client ID and private key from the device. It is recommended that you do it on an Android device, mostly because it is easier to extract from.
By writing this, I am not implying that this library will work with Widevine client IDs and private keys, extracted from a different source (like Chrome or Firefox browsers.)
To do this, you can use the wvdumper/dumper utility, hosted on GitHub.
Download FFmpeg and install it (put it into PATH environment variable). It is used for decrypting the song file itself.
Usage
import fs from 'fs';
import SpotifyDL from 's-dl';
const clientId = fs.readFileSync('client_id.bin');
const privateKey = fs.readFileSync('private_key.pem');
const cookies = fs.readFileSync('cookies-spotify-com.txt')
const spotifyDl = new SpotifyDL({
clientId, // required
cookies, // required
premium: false, // not required, false by default
privateKey, // required
});
(async function() {
// downloadTrack will always pipe out a WAV-formatted audio file.
let res = await spotifyDl.downloadTrack('SPOTIFY-TRACK-ID-HERE');
res.stream.pipe(fs.createWriteStream('track.wav'));
// it's going to close ffmpeg after the duration of the track + 5
// seconds by default. you can change that.
res = await spotifyDl.downloadTrack('SPOTIFY-TRACK-ID-HERE', {
timeout: 60 // 0 for no timeout
});
res.stream.pipe(fs.createWriteStream('track2.wav'))
// or if you want just the decryption key and the stream URL
res = await spotifyDl.downloadTrack('SPOTIFY-TRACK-ID-HERE', {
spawn: false
});
console.log(res.decryptionKey, res.streamUrl);
// you can also get the information about the album, the track and
// the playlist.
const album = await spotifyDl.getAlbum('SPOTIFY-ALBUM-ID-HERE');
const track = await spotifyDl.getTrack('SPOTIFY-TRACK-ID-HERE');
const playlist = await spotifyDl.getPlaylist('SPOTIFY-PLAYLIST-ID-HERE');
// getAlbum and getPlaylist will also fetch all of the children
// tracks.
// you can also fetch the (unsynced) lyrics for a specific song.
const lyrics = await spotifyDl.getLyrics('SPOTIFY-TRACK-ID-HERE');
})();
License
s-dl is licensed under Apache-2.0.