Skip to content

yaaaarn/downcloud

Repository files navigation

️️🌧️ downcloud

npm

a simple (and fast) soundcloud downloader.

table of contents

benchmarks

downcloud (2.0.0)      0.851s  █████
yt-dlp (2026.03.17)    2.836s  ███████████████████
music-dl (0.2.1)       6.241s  ███████████████████████████████
soundcloud-dl (1.0.0)  6.434s  ████████████████████████████████
scdl (3.0.5)           7.353s  █████████████████████████████████████

tested on apple m2 mac mini with 1gbps ethernet speed

more data
program command time
scdl (3.0.5) scdl -l https://soundcloud.com/hologura/yoho4 0.84s user 0.33s system 15% cpu 7.353 total
downcloud (2.0.0) downcloud https://soundcloud.com/hologura/yoho4 0.32s user 0.08s system 47% cpu 0.851 total
yt-dlp (2026.03.17) yt-dlp https://soundcloud.com/hologura/yoho4 1.30s user 0.20s system 53% cpu 2.836 total
soundcloud-dl (1.0.0) go run github.com/AYehia0/soundcloud-dl@latest https://soundcloud.com/hologura/yoho4 -b 0.28s user 0.45s system 11% cpu 6.434 total
music-dl (0.2.1) music-dl --url https://soundcloud.com/hologura/yoho4 3.47s user 0.56s system 64% cpu 6.241 total

prerequisites

  • ffmpeg

install

npm

bunx @yaaaarn/downcloud <url>

or install globally:

bun install -g @yaaaarn/downcloud
downcloud <url>

run directly (no install)

bun run start

nix flake

add to your flake.nix inputs:

downcloud = {
  url = "github:yaaaarn/downcloud";
  inputs.nixpkgs.follows = "nixpkgs";
};

then add downcloud.packages.${system}.default to your environment.systemPackages or home-manager packages.

authentication

higher-quality downloads of some tracks are only available for download with a soundcloud oauth token. to get yours:

  1. open soundcloud and log in
  2. open devtools and go to application > storage > cookies > soundcloud.com
  3. find the oauth_token cookie and copy its value
  4. save it:
downcloud set-token <your-token>

you can also provide it on a per-command basis with -t <token> instead of saving it.

on darwin systems you may get an error if running via ssh, where the keychain cannot be unlocked. running the command below will unlock the keychain:

security unlock-keychain ~/Library/Keychains/login.keychain-db

usage

usage: downcloud [options] [url] [command]

a simple (and fast) soundcloud downloader

arguments:
  url                        soundcloud url (auto-detects track, playlist, or artist)
  outfile                    path to save output file (tracks only)

options:
  -t, --token <string>       use a temporary soundcloud oauth token
  -o, --output <directory>   output directory
  -f, --format <format>      output format (mp3, m4a, flac)
  --download-archive <file>  download archive file (skip already archived tracks)
  --sync <file>              sync archive file (download new, remove deleted, rewrite archive)
  --debug                    print ffmpeg execution logs (default: false)
  -V, --version              output the version number
  -h, --help                 display help for command

commands:
  set-token <token>         save a soundcloud oauth token into your keyring
  track [options] <url>     download a track
  playlist [options] <url>  download all tracks from a playlist
  artist [options] <url>    download all tracks from an artist
  help [command]            display help for command

download (auto-detect)

pass any soundcloud url and downcloud will detect whether it's a track, playlist, or artist:

downcloud https://soundcloud.com/hologura/yoho4
downcloud https://soundcloud.com/user/sets/playlist
downcloud https://soundcloud.com/hologura

all the same options are available:

downcloud https://soundcloud.com/hologura/yoho4 -o ./music -f flac

track

usage: downcloud track [options] <url>

download a track

arguments:
  url                        track url
  outfile                    path to save output file

options:
  -t, --token <string>       use a temporary soundcloud oauth token
  -o, --output <directory>   output directory
  -f, --format <format>      output format (mp3, m4a, flac)
  --download-archive <file>  download archive file (skip already archived tracks)
  --sync <file>              sync archive file (download new, remove deleted, rewrite archive)
  --debug                    print ffmpeg execution logs (default: false)
  -h, --help                 display help for command

playlist

usage: downcloud playlist [options] <url>

download all tracks from a playlist

arguments:
  url                        playlist url

options:
  -t, --token <string>       use a temporary soundcloud oauth token
  -o, --output <directory>   output directory (default: playlist name)
  -f, --format <format>      output format (mp3, m4a, flac)
  --download-archive <file>  download archive file (skip already archived tracks)
  --sync <file>              sync archive file (download new, remove deleted, rewrite archive)
  --debug                    print ffmpeg execution logs (default: false)
  -h, --help                 display help for command

artist

usage: downcloud artist [options] <url>

download all tracks from an artist

arguments:
  url                        artist url

options:
  -t, --token <string>       use a temporary soundcloud oauth token
  -o, --output <directory>   output directory (default: artist name)
  -f, --format <format>      output format (mp3, m4a, flac)
  --download-archive <file>  download archive file (skip already archived tracks)
  --sync <file>              sync archive file (download new, remove deleted, rewrite archive)
  --debug                    print ffmpeg execution logs (default: false)
  -h, --help                 display help for command

library api

downcloud can also be used programmatically. the simplest way is with createClient:

track

import { createClient } from "@yaaaarn/downcloud";

const client = await createClient();
const { filePath } = await client.download("https://soundcloud.com/hologura/yoho4");

console.log(`saved to ${filePath}`);

playlist

import { createClient } from "@yaaaarn/downcloud";

const client = await createClient();
const { results, errors } = await client.downloadPlaylist("https://soundcloud.com/user/sets/playlist");

for (const { filePath } of results) {
  console.log(filePath);
}

artist

import { createClient } from "@yaaaarn/downcloud";

const client = await createClient();
const { results, errors } = await client.downloadArtist("https://soundcloud.com/hologura");

for (const { filePath } of results) {
  console.log(filePath);
}

low-level api

if you need more control, you can use the individual functions directly:

import { resolveClientId, resolveUrl, downloadTrack, type Track } from "@yaaaarn/downcloud";

const clientId = await resolveClientId();
const data = await resolveUrl("https://soundcloud.com/hologura/yoho4", clientId) as Track;
const filePath = await downloadTrack(data, { clientId });

exports

export description
createClient(options?) create a pre-configured client with resolved credentials
resolveClientId() resolve a soundcloud client id from their js assets
resolveOauthToken(token?) get oauth token from arg, env, or system keychain
resolveUrl(url, clientId) resolve a soundcloud url to track/playlist data
fetchArtistTracks(url, clientId) fetch all tracks from an artist
downloadTrack(track, options) download a track to a file
printAsciiWaveform(waveformUrl) print an ascii waveform to the console
ArchiveHelper class for download-archive / sync functionality

dev

# enter the dev shell (if using nix)
nix develop

# install dependencies
bun install

# build the binary
bun run build  # produces ./downcloud

license

gpl-3.0 or later

About

a simple (and fast) soundcloud downloader!

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors